Code

noop: Set svn:eol-style to native on all .cpp and .h files under src. (find \( ...
[inkscape.git] / src / extension / internal / javafx-out.cpp
1 /*
2  * A simple utility for exporting Inkscape svg Shapes as JavaFX paths.
3  *
4  *  For information on the JavaFX file format, see:
5  *      https://openjfx.dev.java.net/
6  *
7  * Authors:
8  *   Bob Jamison <ishmal@inkscape.org>
9  *   Silveira Neto <silveiraneto@gmail.com>
10  *   Jim Clarke <Jim.Clarke@sun.com>
11  *
12  * Copyright (C) 2008 Authors
13  *
14  * Released under GNU GPL, read the file 'COPYING' for more information
15  */
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include "javafx-out.h"
22 #include <inkscape.h>
23 #include <inkscape-version.h>
24 #include <sp-path.h>
25 #include <sp-linear-gradient.h>
26 #include <sp-radial-gradient.h>
27 #include <style.h>
28 #include <display/curve.h>
29 #include <display/canvas-bpath.h>
30 #include <svg/svg.h>
31 #include <extension/system.h>
32 #include <2geom/pathvector.h>
33 #include <2geom/rect.h>
34 #include <2geom/bezier-curve.h>
35 #include <2geom/hvlinesegment.h>
36 #include "helper/geom.h"
37 #include "helper/geom-curves.h"
38 #include <io/sys.h>
41 #include <string>
42 #include <stdio.h>
43 #include <stdarg.h>
46 namespace Inkscape
47 {
48 namespace Extension
49 {
50 namespace Internal
51 {
56 //########################################################################
57 //# M E S S A G E S
58 //########################################################################
60 static void err(const char *fmt, ...)
61 {
62     va_list args;
63     g_log(NULL,  G_LOG_LEVEL_WARNING, "javafx-out err: ");
64     va_start(args, fmt);
65     g_logv(NULL, G_LOG_LEVEL_WARNING, fmt, args);
66     va_end(args);
67     g_log(NULL,  G_LOG_LEVEL_WARNING, "\n");
68 }
71 //########################################################################
72 //# U T I L I T Y
73 //########################################################################
75 /**
76  * Got this method from Bulia, and modified it a bit.  It basically
77  * starts with this style, gets its SPObject parent, walks up the object
78  * tree and finds all of the opacities and multiplies them.
79  *
80  * We use this for our "flat" object output.  If the code is modified
81  * to reflect a tree of <groups>, then this will be unneccessary.
82  */
83 static double effective_opacity(const SPStyle *style)
84 {
85     double val = 1.0;
86     for (SPObject const *obj = style->object; obj ; obj = obj->parent)
87         {
88         style = SP_OBJECT_STYLE(obj);
89         if (style)
90             val *= SP_SCALE24_TO_FLOAT(style->opacity.value);
91         }
92     return val;
93 }
95 //########################################################################
96 //# OUTPUT FORMATTING
97 //########################################################################
100 /**
101  * We want to control floating output format.
102  * Especially to avoid localization. (decimal ',' for example)
103  */
104 static JavaFXOutput::String dstr(double d)
106     char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
107     g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
108                   "%.8f", (gdouble)d);
109     JavaFXOutput::String s = dbuf;
110     return s;
113 #define DSTR(d) (dstr(d).c_str())
116 /**
117  * Format a double as an integer
118  */
119 static JavaFXOutput::String istr(double d)
121     char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
122     g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
123                   "%.0f", (gdouble)d);
124     JavaFXOutput::String s = dbuf;
125     return s;
128 #define ISTR(d) (istr(d).c_str())
131 /**
132  * Format an rgba() string
133  */
134 static JavaFXOutput::String rgba(guint32 rgba)
136     unsigned int r = SP_RGBA32_R_U(rgba);
137     unsigned int g = SP_RGBA32_G_U(rgba);
138     unsigned int b = SP_RGBA32_B_U(rgba);
139     unsigned int a = SP_RGBA32_A_U(rgba);
140     char buf[80];
141     snprintf(buf, 79, "Color.rgb(0x%02x, 0x%02x, 0x%02x, %s)",
142                            r, g, b, DSTR((double)a/256.0));
143     JavaFXOutput::String s = buf;
144     return s;
148 /**
149  * Format an rgba() string for a color and a 0.0-1.0 alpha
150  */
151 static JavaFXOutput::String rgba(SPColor color, gdouble alpha)
153     return rgba(color.toRGBA32(alpha));
156 /**
157  * Map Inkscape linecap styles to JavaFX
158  */
159 static JavaFXOutput::String getStrokeLineCap(unsigned value) {
160     switch(value) {
161         case SP_STROKE_LINECAP_BUTT:
162             return "StrokeLineCap.BUTT";
163         case SP_STROKE_LINECAP_ROUND:
164             return "StrokeLineCap.ROUND";
165         case SP_STROKE_LINECAP_SQUARE:
166             return "StrokeLineCap.SQUARE";
167         default:
168             return "INVALID LINE CAP";
169     }
173 /**
174  * Map Inkscape linejoin styles to JavaFX
175  */
176 static JavaFXOutput::String getStrokeLineJoin(unsigned value) {
177     switch(value) {
178         case SP_STROKE_LINEJOIN_MITER:
179             return "StrokeLineJoin.MITER";
180         case SP_STROKE_LINEJOIN_ROUND:
181             return "StrokeLineJoin.ROUND";
182         case SP_STROKE_LINEJOIN_BEVEL:
183             return "StrokeLineJoin.BEVEL";
184         default:
185             return "INVALID LINE JOIN";
186     }
190 /**
191  * Replace illegal characters for JavaFX for a underscore.
192  */
193 static JavaFXOutput::String sanatize(const JavaFXOutput::String &badstr){
194     JavaFXOutput::String good(badstr);
195     for (int pos = 0; pos < badstr.length(); ++pos )
196         if((badstr.at(pos)=='-')||(badstr.at(pos)==' '))
197             good.replace(pos, 1, "_");
198     return good;
201 /**
202  *  Output data to the buffer, printf()-style
203  */
204 void JavaFXOutput::out(const char *fmt, ...)
206     va_list args;
207     va_start(args, fmt);
208     gchar *output = g_strdup_vprintf(fmt, args);
209     va_end(args);
210     outbuf.append(output);
211     g_free(output);
216 /**
217  * Output the file header
218  */
219 bool JavaFXOutput::doHeader()
221     time_t tim = time(NULL);
222     out("/*###################################################################\n");
223     out("### This JavaFX document was generated by Inkscape\n");
224     out("### http://www.inkscape.org\n");
225     out("### Created: %s",   ctime(&tim));
226     out("### Version: %s\n", Inkscape::version_string);
227     out("#####################################################################\n");
228     out("### NOTES:\n");
229     out("### ============\n");
230     out("### JavaFX information can be found at\n");
231     out("### hhttps://openjfx.dev.java.net\n");
232     out("###\n");
233     out("### If you have any problems with this output, please see the\n");
234     out("### Inkscape project at http://www.inkscape.org, or visit\n");
235     out("### the #inkscape channel on irc.freenode.net . \n");
236     out("###\n");
237     out("###################################################################*/\n");
238     out("\n\n");
239     out("/*###################################################################\n");
240     out("##   Exports in this file\n");
241     out("##==========================\n");
242     out("##    Shapes   : %d\n", nrShapes);
243     out("##    Nodes    : %d\n", nrNodes);
244     out("###################################################################*/\n");
245     out("\n\n");
247     // import javafx libraries we can need
248     out("import javafx.application.*;\n");
249     out("import javafx.scene.*;\n");
250     out("import javafx.scene.geometry.*;\n");
251     out("import javafx.scene.transform.*;\n");
252     out("import javafx.scene.paint.*;\n");
253     out("\n");
255     out("\n\n");
257     // Creates a class extended from CustomNode
258     out("public class %s extends CustomNode {\n", name.c_str());
260     return true;
265 /**
266  *  Output the file footer
267  */
268 bool JavaFXOutput::doTail()
270     float border = 25.0;
272     // Write the tail of CustomNode
273     out("           ] // content\n");
274     out("           transform: Translate { x : %s, y : %s }\n",
275                   DSTR((-minx) + border), DSTR((-miny) + border) );
276     out("       } // Group\n");
277     out("   } // function create()\n");
278     out("} // class %s\n", name.c_str());
279     out("\n");
281     // Frame
282     out("Frame {\n");
283     out("    title: \"%s\"\n", name.c_str());
284     out("    width: %s\n",  ISTR(maxx-minx + border * 2.0));
285     out("    height: %s\n", ISTR(maxy-miny + border * 2.0));
286     out("    visible: true\n");
288     // Stage
289     out("    stage: Stage {\n");
290     out("        content: %s{}\n", name.c_str());
291     out("    } // Stage\n");
293     out("} // Frame\n");
295     out("\n");
297     out("/*###################################################################\n");
298     out("### E N D   C L A S S    %s\n", name.c_str());
299     out("###################################################################*/\n");
300     out("\n\n");
301     return true;
306 /**
307  *  Output gradient information to the buffer
308  */
309 bool JavaFXOutput::doGradient(SPGradient *grad, const String &id)
311     String jfxid = sanatize(id);
313     if (SP_IS_LINEARGRADIENT(grad))
314         {
315         SPLinearGradient *g = SP_LINEARGRADIENT(grad);
316         out("    /* create LinearGradient for %s */\n", jfxid.c_str());
317         out("    private function %s(): LinearGradient {\n",  jfxid.c_str());
318         out("        LinearGradient {\n");
319         std::vector<SPGradientStop> stops = g->vector.stops;
320         if (stops.size() > 0)
321             {
322             out("            stops:\n");
323             out("                [\n");
324             for (unsigned int i = 0 ; i<stops.size() ; i++)
325                 {
326                 SPGradientStop stop = stops[i];
327                 out("                Stop {\n");
328                 out("                    offset: %s\n", DSTR(stop.offset));
329                 out("                    color: %s\n",  rgba(stop.color, stop.opacity).c_str());
330                 out("                },\n");
331                 }
332             out("            ]\n");
333             }
334         out("        };\n");
335         out("    } // end LinearGradient: %s\n", jfxid.c_str());
336         out("\n\n");
337         }
338     else if (SP_IS_RADIALGRADIENT(grad))
339         {
340         SPRadialGradient *g = SP_RADIALGRADIENT(grad);
341         out("    /* create RadialGradient for %s */\n", jfxid.c_str());
342         out("    private function %s() {\n", jfxid.c_str());
343         out("        RadialGradient {\n");
344         out("            centerX: %s\n", DSTR(g->cx.value));
345         out("            centerY: %s\n", DSTR(g->cy.value));
346         out("            focusX: %s\n",  DSTR(g->fx.value));
347         out("            focusY: %s\n",  DSTR(g->fy.value));
348         out("            radius: %s\n",  DSTR(g->r.value ));
349         std::vector<SPGradientStop> stops = g->vector.stops;
350         if (stops.size() > 0)
351             {
352             out("            stops:\n");
353             out("            [\n");
354             for (unsigned int i = 0 ; i<stops.size() ; i++)
355                 {
356                 SPGradientStop stop = stops[i];
357                 out("                Stop {\n");
358                 out("                    offset: %s\n", DSTR(stop.offset));
359                 out("                    color: %s\n",  rgba(stop.color, stop.opacity).c_str());
360                 out("                },\n");
361                 }
362             out("            ]\n");
363             }
364         out("        };\n");
365         out("    } // end RadialGradient: %s\n", jfxid.c_str());
366         out("\n\n");
367         }
368     else
369         {
370         err("Unknown gradient type for '%s'\n", jfxid.c_str());
371         return false;
372         }
375     return true;
381 /**
382  *  Output an element's style attribute
383  */
384 bool JavaFXOutput::doStyle(SPStyle *style)
386     if (!style)
387         return true;
389     out("            opacity: %s\n", DSTR(effective_opacity(style)));
391     /**
392      * Fill
393      */
394     SPIPaint fill = style->fill;
395     if (fill.isColor())
396         {
397         // see color.h for how to parse SPColor
398         out("            fill: %s\n",
399             rgba(fill.value.color, SP_SCALE24_TO_FLOAT(style->fill_opacity.value)).c_str());
400         }
401     else if (fill.isPaintserver()){
402         if (fill.value.href && fill.value.href->getURI() ){
403             String uri = fill.value.href->getURI()->toString();
404             /* trim the anchor '#' from the front */
405             if (uri.size() > 0 && uri[0]=='#')
406                 uri = uri.substr(1);
407             out("            fill: %s()\n", sanatize(uri).c_str());
408         }
409     }
412     /**
413      * Stroke
414      */
415     /**
416      *NOTE:  Things in style we can use:
417      * SPIPaint stroke;
418      * SPILength stroke_width;
419      * SPIEnum stroke_linecap;
420      * SPIEnum stroke_linejoin;
421      * SPIFloat stroke_miterlimit;
422      * NRVpathDash stroke_dash;
423      * unsigned stroke_dasharray_set : 1;
424      * unsigned stroke_dasharray_inherit : 1;
425      * unsigned stroke_dashoffset_set : 1;
426      * SPIScale24 stroke_opacity;
427      */
428     if (style->stroke_opacity.value > 0)
429         {
430         SPIPaint stroke = style->stroke;
431         out("            stroke: %s\n",
432             rgba(stroke.value.color, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value)).c_str());
433         double strokewidth = style->stroke_width.value;
434         unsigned linecap   = style->stroke_linecap.value;
435         unsigned linejoin  = style->stroke_linejoin.value;
436         out("            strokeWidth: %s\n",      DSTR(strokewidth));
437         out("            strokeLineCap: %s\n",    getStrokeLineCap(linecap).c_str());
438         out("            strokeLineJoin: %s\n",   getStrokeLineJoin(linejoin).c_str());
439         out("            strokeMiterLimit: %s\n", DSTR(style->stroke_miterlimit.value));
440         if(style->stroke_dasharray_set) {
441            if(style->stroke_dashoffset_set) {
442                out("            strokeDashOffset: %s\n", DSTR(style->stroke_dash.offset));
443            }
444            out("            strokeDashArray: [ ");
445            for(int i = 0; i < style->stroke_dash.n_dash; i++ ) {
446                if(i > 0) {
447                    out(", %.2lf", style->stroke_dash.dash[i]);
448                }else {
449                    out(" %.2lf", style->stroke_dash.dash[i]);
450                }
451            }
452            out(" ]\n");
453         }
455         }
457     return true;
461 #if 1
463 /**
464  *  Output the curve data to buffer
465  */
466 bool JavaFXOutput::doCurve(SPItem *item, const String &id)
468     using Geom::X;
469     using Geom::Y;
471     String jfxid = sanatize(id);
473     //### Get the Shape
474     if (!SP_IS_SHAPE(item))//Bulia's suggestion.  Allow all shapes
475         return true;
477     SPShape *shape = SP_SHAPE(item);
478     SPCurve *curve = shape->curve;
479     if (curve->is_empty())
480         return true;
482     nrShapes++;
484     out("    /** path %s */\n", jfxid.c_str());
485     out("    private function %s() : Path {\n",jfxid.c_str());
486     out("        Path {\n");
487     out("            id: \"%s\"\n", jfxid.c_str());
489     /**
490      * Output the style information
491      */
492     if (!doStyle(SP_OBJECT_STYLE(shape)))
493         return false;
495     // convert the path to only lineto's and cubic curveto's:
496     Geom::Scale yflip(1.0, -1.0);
497     Geom::Matrix tf = sp_item_i2d_affine(item) * yflip;
498     Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );
500     //Count the NR_CURVETOs/LINETOs (including closing line segment)
501     guint segmentCount = 0;
502     for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {
503         segmentCount += (*it).size();
504         if (it->closed())
505             segmentCount += 1;
506     }
508     out("            elements: [\n");
510     unsigned int segmentNr = 0;
512     nrNodes += segmentCount;
514     Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() );
516     /**
517      * For all Subpaths in the <path>
518      */
519     for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)
520         {
521         Geom::Point p = pit->front().initialPoint();
522         cminmax.expandTo(p);
523         out("                MoveTo {\n");
524         out("                    x: %s\n", DSTR(p[X]));
525         out("                    y: %s\n", DSTR(p[Y]));
526         out("                },\n");
528         /**
529          * For all segments in the subpath
530          */
531         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
532             {
533             //### LINE
534             if( dynamic_cast<Geom::LineSegment  const *> (&*cit) ||
535                 dynamic_cast<Geom::HLineSegment const *> (&*cit) ||
536                 dynamic_cast<Geom::VLineSegment const *> (&*cit) )
537                 {
538                 Geom::Point p = cit->finalPoint();
539                 out("                LineTo {\n");
540                 out("                    x: %s\n", DSTR(p[X]));
541                 out("                    y: %s\n", DSTR(p[Y]));
542                 out("                },\n");
543                 nrNodes++;
544                 }
545             //### BEZIER
546             else if(Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
547                 {
548                 std::vector<Geom::Point> points = cubic->points();
549                 Geom::Point p1 = points[1];
550                 Geom::Point p2 = points[2];
551                 Geom::Point p3 = points[3];
552                 out("                CurveTo {\n");
553                 out("                    controlX1: %s\n", DSTR(p1[X]));
554                 out("                    controlY1: %s\n", DSTR(p1[Y]));
555                 out("                    controlX2: %s\n", DSTR(p2[X]));
556                 out("                    controlY2: %s\n", DSTR(p2[Y]));
557                 out("                    x: %s\n",         DSTR(p3[X]));
558                 out("                    y: %s\n",         DSTR(p3[Y]));
559                 out("                },\n");
560                 nrNodes++;
561                 }
562             else
563                 {
564                 g_error ("logical error, because pathv_to_linear_and_cubic_beziers was used");
565                 }
566             segmentNr++;
567             cminmax.expandTo(cit->finalPoint());
568             }
569         if (pit->closed())
570             {
571             out("                ClosePath {},\n");
572             }
573         }
575     out("            ] // elements\n");
576     out("        }; // Path\n");
577     out("    } // end path %s\n\n", jfxid.c_str());
579     double cminx = cminmax.min()[X];
580     double cmaxx = cminmax.max()[X];
581     double cminy = cminmax.min()[Y];
582     double cmaxy = cminmax.max()[Y];
584     if (cminx < minx)
585         minx = cminx;
586     if (cmaxx > maxx)
587         maxx = cmaxx;
588     if (cminy < miny)
589         miny = cminy;
590     if (cmaxy > maxy)
591         maxy = cmaxy;
593     return true;
598 #else
600 /**
601  *  Output the curve data to buffer
602  */
603 bool JavaFXOutput::doCurve(SPItem *item, const String &id)
605     using Geom::X;
606     using Geom::Y;
608     //### Get the Shape
609     if (!SP_IS_SHAPE(item))//Bulia's suggestion.  Allow all shapes
610         return true;
612     SPShape *shape = SP_SHAPE(item);
613     SPCurve *curve = shape->curve;
614     if (curve->is_empty())
615         return true;
617     nrShapes++;
619     out("        SVGPath \n");
620     out("        {\n");
621     out("        id: \"%s\"\n", id.c_str());
623     /**
624      * Output the style information
625      */
626     if (!doStyle(SP_OBJECT_STYLE(shape)))
627         return false;
629     // convert the path to only lineto's and cubic curveto's:
630     Geom::Scale yflip(1.0, -1.0);
631     Geom::Matrix tf = sp_item_i2d_affine(item) * yflip;
632     Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );
633     
634     //Count the NR_CURVETOs/LINETOs (including closing line segment)
635     nrNodes = 0;
636     for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {
637         nrNodes += (*it).size();
638         if (it->closed())
639             nrNodes += 1;
640     }
642     char *dataStr = sp_svg_write_path(pathv);
643     out("        content: \"%s\"\n", dataStr);
644     free(dataStr);
646     Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() ); 
648     /**
649      * Get the Min and Max X and Y extends for the Path. 
650      * ....For all Subpaths in the <path>
651      */      
652     for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)
653         {
654         cminmax.expandTo(pit->front().initialPoint());
655         /**
656          * For all segments in the subpath
657          */                      
658         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
659             {
660             cminmax.expandTo(cit->finalPoint());
661             }
662         }
664     out("        },\n");
666     double cminx = cminmax.min()[X];
667     double cmaxx = cminmax.max()[X];
668     double cminy = cminmax.min()[Y];
669     double cmaxy = cminmax.max()[Y];
671     if (cminx < minx)
672         minx = cminx;
673     if (cmaxx > maxx)
674         maxx = cmaxx;
675     if (cminy < miny)
676         miny = cminy;
677     if (cmaxy > maxy)
678         maxy = cmaxy;
680     return true;
685 #endif  /* #if o */
689 /**
690  *  Output the tree data to buffer
691  */
692 bool JavaFXOutput::doTreeRecursive(SPDocument *doc, SPObject *obj)
694     /**
695      * Check the type of node and process
696      */
697     String id;
698     if (!obj->id)
699         {
700         char buf[16];
701         sprintf(buf, "id%d", idindex++);
702         id = buf;
703         }
704     else
705         {
706         id = obj->id;
707         }
708     if (SP_IS_ITEM(obj))
709         {
710         SPItem *item = SP_ITEM(obj);
711         if (!doCurve(item, id))
712             return false;
713         }
714     else if (SP_IS_GRADIENT(obj))
715         {
716         SPGradient *grad = SP_GRADIENT(obj);
717         if (!doGradient(grad, id))
718             return false;
719         }
721     /**
722      * Descend into children
723      */      
724     for (SPObject *child = obj->firstChild() ; child ; child = child->next)
725         {
726                 if (!doTreeRecursive(doc, child))
727                     return false;
728                 }
730     return true;
734 /**
735  *  Output the curve data to buffer
736  */
737 bool JavaFXOutput::doTree(SPDocument *doc)
740     double bignum = 1000000.0;
741     minx  =  bignum;
742     maxx  = -bignum;
743     miny  =  bignum;
744     maxy  = -bignum;
746     if (!doTreeRecursive(doc, doc->root))
747         return false;
749     return true;
754 bool JavaFXOutput::doBody(SPDocument *doc, SPObject *obj)
756     /**
757      * Check the type of node and process
758      */
759     String id;
760     if (!obj->id)
761         {
762         char buf[16];
763         sprintf(buf, "id%d", idindex++);
764         id = buf;
765         }
766     else
767         {
768         id = obj->id;
769         }
771     if (SP_IS_ITEM(obj)) {
772         SPItem *item = SP_ITEM(obj);
773         //### Get the Shape
774         if (SP_IS_SHAPE(item)) {//Bulia's suggestion.  Allow all shapes
775             SPShape *shape = SP_SHAPE(item);
776             SPCurve *curve = shape->curve;
777             if (!curve->is_empty())
778                 out("               %s(),\n", id.c_str());
779         }
780     }
781     else if (SP_IS_GRADIENT(obj)) {
782         //TODO: what to do with Gradient within body?????
783         //SPGradient *grad = SP_GRADIENT(reprobj);
784         //if (!doGradient(grad, id))
785         //    return false;
786     }
788     /**
789      * Descend into children
790      */
791     for (SPObject *child = obj->firstChild() ; child ; child = child->next)
792         {
793                 if (!doBody(doc, child))
794                     return false;
795                 }
797     return true;
802 //########################################################################
803 //# M A I N    O U T P U T
804 //########################################################################
808 /**
809  *  Set values back to initial state
810  */
811 void JavaFXOutput::reset()
813     nrNodes    = 0;
814     nrShapes   = 0;
815     idindex    = 0;
816     name.clear();
817     outbuf.clear();
818     foutbuf.clear();
823 /**
824  * Saves the <paths> of an Inkscape SVG file as JavaFX spline definitions
825  */
826 bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)
828     reset();
831     name = Glib::path_get_basename(filename_utf8);
832     int pos = name.find('.');
833     if (pos > 0)
834         name = name.substr(0, pos);
837     //###### SAVE IN JAVAFX FORMAT TO BUFFER
838     //# Lets do the curves first, to get the stats
840     if (!doTree(doc))
841         return false;
842     String curveBuf = outbuf;
843     outbuf.clear();
845     if (!doHeader())
846         return false;
848     outbuf.append(curveBuf);
850 #ifdef JAVAFX_SDK_1_0
851     out("   override function create(): Node {\n");
852 #else
853     out("   public function create(): Node {\n");
854 #endif
855     out("       Group {\n");
856     out("           content: [\n");
857     idindex    = 0;
859     doBody(doc, doc->root);
861     if (!doTail())
862         return false;
866     //###### WRITE TO FILE
867     FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");
868     if (!f)
869         {
870         err("Could open JavaFX file '%s' for writing", filename_utf8);
871         return false;
872         }
874     for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); iter++)
875         {
876         fputc(*iter, f);
877         }
878         
879     fclose(f);
880     
881     return true;
887 //########################################################################
888 //# EXTENSION API
889 //########################################################################
893 #include "clear-n_.h"
897 /**
898  * API call to save document
899 */
900 void
901 JavaFXOutput::save(Inkscape::Extension::Output */*mod*/,
902                         SPDocument *doc, gchar const *filename_utf8)
904     /* N.B. The name `filename_utf8' represents the fact that we want it to be in utf8; whereas in
905      * fact we know that some callers of Extension::save pass something in the filesystem's
906      * encoding, while others do g_filename_to_utf8 before calling.
907      *
908      * In terms of safety, it's best to make all callers pass actual filenames, since in general
909      * one can't round-trip from filename to utf8 back to the same filename.  Whereas the argument
910      * for passing utf8 filenames is one of convenience: we often want to pass to g_warning or
911      * store as a string (rather than a byte stream) in XML, or the like. */
912     if (!saveDocument(doc, filename_utf8))
913         {
914         g_warning("Could not save JavaFX file '%s'", filename_utf8);
915         }
920 /**
921  * Make sure that we are in the database
922  */
923 bool JavaFXOutput::check (Inkscape::Extension::Extension */*module*/)
925     /* We don't need a Key
926     if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_JFX))
927         return FALSE;
928     */
930     return true;
935 /**
936  * This is the definition of JavaFX output.  This function just
937  * calls the extension system with the memory allocated XML that
938  * describes the data.
939 */
940 void
941 JavaFXOutput::init()
943     Inkscape::Extension::build_from_mem(
944         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
945             "<name>" N_("JavaFX Output") "</name>\n"
946             "<id>org.inkscape.output.jfx</id>\n"
947             "<output>\n"
948                 "<extension>.fx</extension>\n"
949                 "<mimetype>text/x-javafx-script</mimetype>\n"
950                 "<filetypename>" N_("JavaFX (*.fx)") "</filetypename>\n"
951                 "<filetypetooltip>" N_("JavaFX Raytracer File") "</filetypetooltip>\n"
952             "</output>\n"
953         "</inkscape-extension>",
954         new JavaFXOutput());
961 }  // namespace Internal
962 }  // namespace Extension
963 }  // namespace Inkscape
966 /*
967   Local Variables:
968   mode:c++
969   c-file-style:"stroustrup"
970   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
971   indent-tabs-mode:nil
972   fill-column:99
973   End:
974 */
975 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :