Code

Pot and Dutch translation update
[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  *   Jon A. Cruz <jon@joncruz.org>
12  *
13  * Copyright (C) 2008,2009 Authors
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 #include "javafx-out.h"
23 #include <inkscape.h>
24 #include <inkscape-version.h>
25 #include <sp-path.h>
26 #include <sp-linear-gradient.h>
27 #include <sp-radial-gradient.h>
28 #include <style.h>
29 #include <display/curve.h>
30 #include <display/canvas-bpath.h>
31 #include <svg/svg.h>
32 #include <extension/system.h>
33 #include <2geom/pathvector.h>
34 #include <2geom/rect.h>
35 #include <2geom/bezier-curve.h>
36 #include <2geom/hvlinesegment.h>
37 #include "helper/geom.h"
38 #include "helper/geom-curves.h"
39 #include <io/sys.h>
42 #include <string>
43 #include <stdio.h>
44 #include <stdarg.h>
47 namespace Inkscape
48 {
49 namespace Extension
50 {
51 namespace Internal
52 {
57 //########################################################################
58 //# M E S S A G E S
59 //########################################################################
61 static void err(const char *fmt, ...)
62 {
63     va_list args;
64     g_log(NULL,  G_LOG_LEVEL_WARNING, "javafx-out err: ");
65     va_start(args, fmt);
66     g_logv(NULL, G_LOG_LEVEL_WARNING, fmt, args);
67     va_end(args);
68     g_log(NULL,  G_LOG_LEVEL_WARNING, "\n");
69 }
72 //########################################################################
73 //# U T I L I T Y
74 //########################################################################
76 /**
77  * Got this method from Bulia, and modified it a bit.  It basically
78  * starts with this style, gets its SPObject parent, walks up the object
79  * tree and finds all of the opacities and multiplies them.
80  *
81  * We use this for our "flat" object output.  If the code is modified
82  * to reflect a tree of <groups>, then this will be unneccessary.
83  */
84 static double effective_opacity(const SPStyle *style)
85 {
86     double val = 1.0;
87     for (SPObject const *obj = style->object; obj ; obj = obj->parent)
88         {
89         style = SP_OBJECT_STYLE(obj);
90         if (style) {
91             val *= SP_SCALE24_TO_FLOAT(style->opacity.value);
92         }
93         }
94     return val;
95 }
97 //########################################################################
98 //# OUTPUT FORMATTING
99 //########################################################################
102 /**
103  * We want to control floating output format.
104  * Especially to avoid localization. (decimal ',' for example)
105  */
106 static JavaFXOutput::String dstr(double d)
108     char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
109     g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
110                   "%.8f", (gdouble)d);
111     JavaFXOutput::String s = dbuf;
112     return s;
115 #define DSTR(d) (dstr(d).c_str())
118 /**
119  * Format a double as an integer
120  */
121 static JavaFXOutput::String istr(double d)
123     char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
124     g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
125                   "%.0f", (gdouble)d);
126     JavaFXOutput::String s = dbuf;
127     return s;
130 #define ISTR(d) (istr(d).c_str())
133 /**
134  * Format an rgba() string
135  */
136 static JavaFXOutput::String rgba(guint32 rgba)
138     unsigned int r = SP_RGBA32_R_U(rgba);
139     unsigned int g = SP_RGBA32_G_U(rgba);
140     unsigned int b = SP_RGBA32_B_U(rgba);
141     unsigned int a = SP_RGBA32_A_U(rgba);
142     char buf[80];
143     snprintf(buf, 79, "Color.rgb(0x%02x, 0x%02x, 0x%02x, %s)",
144                            r, g, b, DSTR((double)a/255.0));
145     JavaFXOutput::String s = buf;
146     return s;
150 /**
151  * Format an rgba() string for a color and a 0.0-1.0 alpha
152  */
153 static JavaFXOutput::String rgba(SPColor color, gdouble alpha)
155     return rgba(color.toRGBA32(alpha));
158 /**
159  * Map Inkscape linecap styles to JavaFX
160  */
161 static JavaFXOutput::String getStrokeLineCap(unsigned value) {
162     switch(value) {
163         case SP_STROKE_LINECAP_BUTT:
164             return "StrokeLineCap.BUTT";
165         case SP_STROKE_LINECAP_ROUND:
166             return "StrokeLineCap.ROUND";
167         case SP_STROKE_LINECAP_SQUARE:
168             return "StrokeLineCap.SQUARE";
169         default:
170             return "INVALID LINE CAP";
171     }
175 /**
176  * Map Inkscape linejoin styles to JavaFX
177  */
178 static JavaFXOutput::String getStrokeLineJoin(unsigned value) {
179     switch(value) {
180         case SP_STROKE_LINEJOIN_MITER:
181             return "StrokeLineJoin.MITER";
182         case SP_STROKE_LINEJOIN_ROUND:
183             return "StrokeLineJoin.ROUND";
184         case SP_STROKE_LINEJOIN_BEVEL:
185             return "StrokeLineJoin.BEVEL";
186         default:
187             return "INVALID LINE JOIN";
188     }
192 /**
193  * Replace illegal characters for JavaFX for a underscore.
194  */
195 static JavaFXOutput::String sanatize(const JavaFXOutput::String &badstr){
196     JavaFXOutput::String good(badstr);
197     for (int pos = 0; pos < static_cast<int>(badstr.length()); ++pos )
198         if ((badstr.at(pos)=='-')||(badstr.at(pos)==' ')) {
199             good.replace(pos, 1, "_");
200         }
201     return good;
204 /**
205  *  Output data to the buffer, printf()-style
206  */
207 void JavaFXOutput::out(const char *fmt, ...)
209     va_list args;
210     va_start(args, fmt);
211     gchar *output = g_strdup_vprintf(fmt, args);
212     va_end(args);
213     outbuf.append(output);
214     g_free(output);
219 /**
220  * Output the file header
221  */
222 bool JavaFXOutput::doHeader()
224     time_t tim = time(NULL);
225     out("/*###################################################################\n");
226     out("### This JavaFX document was generated by Inkscape\n");
227     out("### http://www.inkscape.org\n");
228     out("### Created: %s",   ctime(&tim));
229     out("### Version: %s\n", Inkscape::version_string);
230     out("#####################################################################\n");
231     out("### NOTES:\n");
232     out("### ============\n");
233     out("### JavaFX information can be found at\n");
234     out("### http://www.javafx.com/\n");
235     out("###\n");
236     out("### If you have any problems with this output, please see the\n");
237     out("### Inkscape project at http://www.inkscape.org, or visit\n");
238     out("### the #inkscape channel on irc.freenode.net . \n");
239     out("###\n");
240     out("###################################################################*/\n");
241     out("\n\n");
242     out("/*###################################################################\n");
243     out("##   Exports in this file\n");
244     out("##==========================\n");
245     out("##    Shapes   : %d\n", nrShapes);
246     out("##    Nodes    : %d\n", nrNodes);
247     out("###################################################################*/\n");
248     out("\n\n");
250     // import javafx libraries we can need
251     out("import javafx.scene.*;\n");
252     out("import javafx.scene.shape.*;\n");
253     out("import javafx.scene.transform.*;\n");
254     out("import javafx.scene.paint.*;\n");
255     out("\n");
257     out("\n\n");
259     // Creates a class extended from CustomNode
260     out("public class %s extends CustomNode {\n", name.c_str());
262     return true;
267 /**
268  *  Output the file footer
269  */
270 bool JavaFXOutput::doTail()
272     float border = 25.0;
274     // Write the tail of CustomNode
275     out("           ] // content\n");
276     out("           transforms: Translate { x : %s, y : %s }\n",
277         DSTR((-minx) + border), DSTR((-miny) + border) );
278     out("       } // Group\n");
279     out("   } // function create()\n");
280     out("} // class %s\n", name.c_str());
281     out("\n");
283     // Stage
284 //     out("    stage: Stage {\n");
285 //     out("        content: %s{}\n", name.c_str());
286 //     out("    } // Stage\n");
289     out("\n");
291     out("/*###################################################################\n");
292     out("### E N D   C L A S S    %s\n", name.c_str());
293     out("###################################################################*/\n");
294     out("\n\n");
295     return true;
300 /**
301  *  Output gradient information to the buffer
302  */
303 bool JavaFXOutput::doGradient(SPGradient *grad, const String &id)
305     String jfxid = sanatize(id);
307     if (SP_IS_LINEARGRADIENT(grad))
308         {
309         SPLinearGradient *g = SP_LINEARGRADIENT(grad);
310         out("    /* create LinearGradient for %s */\n", jfxid.c_str());
311         out("    function %s(): LinearGradient {\n",  jfxid.c_str());
312         out("        LinearGradient {\n");
313         std::vector<SPGradientStop> stops = g->vector.stops;
314         if (stops.size() > 0)
315             {
316             out("            stops:\n");
317             out("                [\n");
318             for (unsigned int i = 0 ; i<stops.size() ; i++)
319                 {
320                 SPGradientStop stop = stops[i];
321                 out("                Stop {\n");
322                 out("                    offset: %s\n", DSTR(stop.offset));
323                 out("                    color: %s\n",  rgba(stop.color, stop.opacity).c_str());
324                 out("                },\n");
325                 }
326             out("            ]\n");
327             }
328         out("        };\n");
329         out("    } // end LinearGradient: %s\n", jfxid.c_str());
330         out("\n\n");
331         }
332     else if (SP_IS_RADIALGRADIENT(grad))
333         {
334         SPRadialGradient *g = SP_RADIALGRADIENT(grad);
335         out("    /* create RadialGradient for %s */\n", jfxid.c_str());
336         out("    function %s() {\n", jfxid.c_str());
337         out("        RadialGradient {\n");
338         out("            centerX: %s\n", DSTR(g->cx.value));
339         out("            centerY: %s\n", DSTR(g->cy.value));
340         out("            focusX: %s\n",  DSTR(g->fx.value));
341         out("            focusY: %s\n",  DSTR(g->fy.value));
342         out("            radius: %s\n",  DSTR(g->r.value ));
343         std::vector<SPGradientStop> stops = g->vector.stops;
344         if (stops.size() > 0)
345             {
346             out("            stops:\n");
347             out("            [\n");
348             for (unsigned int i = 0 ; i<stops.size() ; i++)
349                 {
350                 SPGradientStop stop = stops[i];
351                 out("                Stop {\n");
352                 out("                    offset: %s\n", DSTR(stop.offset));
353                 out("                    color: %s\n",  rgba(stop.color, stop.opacity).c_str());
354                 out("                },\n");
355                 }
356             out("            ]\n");
357             }
358         out("        };\n");
359         out("    } // end RadialGradient: %s\n", jfxid.c_str());
360         out("\n\n");
361         }
362     else
363         {
364         err("Unknown gradient type for '%s'\n", jfxid.c_str());
365         return false;
366         }
369     return true;
375 /**
376  *  Output an element's style attribute
377  */
378 bool JavaFXOutput::doStyle(SPStyle *style)
380     if (!style) {
381         return true;
382     }
384     out("            opacity: %s\n", DSTR(effective_opacity(style)));
386     /**
387      * Fill
388      */
389     SPIPaint const &fill = style->fill;
390     if (fill.isColor())
391         {
392         // see color.h for how to parse SPColor
393         out("            fill: %s\n",
394             rgba(fill.value.color, SP_SCALE24_TO_FLOAT(style->fill_opacity.value)).c_str());
395         }
396     else if (fill.isPaintserver()){
397         if (fill.value.href && fill.value.href->getURI() ){
398             String uri = fill.value.href->getURI()->toString();
399             /* trim the anchor '#' from the front */
400             if (uri.size() > 0 && uri[0]=='#') {
401                 uri = uri.substr(1);
402             }
403             out("            fill: %s()\n", sanatize(uri).c_str());
404         }
405     }
408     /**
409      * Stroke
410      */
411     /**
412      *NOTE:  Things in style we can use:
413      * SPIPaint stroke;
414      * SPILength stroke_width;
415      * SPIEnum stroke_linecap;
416      * SPIEnum stroke_linejoin;
417      * SPIFloat stroke_miterlimit;
418      * NRVpathDash stroke_dash;
419      * unsigned stroke_dasharray_set : 1;
420      * unsigned stroke_dasharray_inherit : 1;
421      * unsigned stroke_dashoffset_set : 1;
422      * SPIScale24 stroke_opacity;
423      */
424     if (style->stroke_opacity.value > 0)
425         {
426         SPIPaint const &stroke = style->stroke;
427         out("            stroke: %s\n",
428             rgba(stroke.value.color, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value)).c_str());
429         double strokewidth = style->stroke_width.value;
430         unsigned linecap   = style->stroke_linecap.value;
431         unsigned linejoin  = style->stroke_linejoin.value;
432         out("            strokeWidth: %s\n",      DSTR(strokewidth));
433         out("            strokeLineCap: %s\n",    getStrokeLineCap(linecap).c_str());
434         out("            strokeLineJoin: %s\n",   getStrokeLineJoin(linejoin).c_str());
435         out("            strokeMiterLimit: %s\n", DSTR(style->stroke_miterlimit.value));
436         if (style->stroke_dasharray_set) {
437            if (style->stroke_dashoffset_set) {
438                out("            strokeDashOffset: %s\n", DSTR(style->stroke_dash.offset));
439            }
440            out("            strokeDashArray: [ ");
441            for(int i = 0; i < style->stroke_dash.n_dash; i++ ) {
442                if (i > 0) {
443                    out(", %.2lf", style->stroke_dash.dash[i]);
444                }else {
445                    out(" %.2lf", style->stroke_dash.dash[i]);
446                }
447            }
448            out(" ]\n");
449         }
451         }
453     return true;
457 #if 1
459 /**
460  *  Output the curve data to buffer
461  */
462 bool JavaFXOutput::doCurve(SPItem *item, const String &id)
464     using Geom::X;
465     using Geom::Y;
467     String jfxid = sanatize(id);
469     //### Get the Shape
470     if (!SP_IS_SHAPE(item)) { //Bulia's suggestion.  Allow all shapes
471         return true;
472     }
474     SPShape *shape = SP_SHAPE(item);
475     SPCurve *curve = shape->curve;
476     if (curve->is_empty()) {
477         return true;
478     }
480     nrShapes++;
482     out("    /** path %s */\n", jfxid.c_str());
483     out("    function %s() : Path {\n",jfxid.c_str());
484     out("        Path {\n");
485     out("            id: \"%s\"\n", jfxid.c_str());
487     /**
488      * Output the style information
489      */
490     if (!doStyle(SP_OBJECT_STYLE(shape))) {
491         return false;
492     }
494     // convert the path to only lineto's and cubic curveto's:
495     Geom::Scale yflip(1.0, -1.0);
496     Geom::Matrix tf = sp_item_i2d_affine(item) * yflip;
497     Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );
499     //Count the NR_CURVETOs/LINETOs (including closing line segment)
500     guint segmentCount = 0;
501     for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {
502         segmentCount += (*it).size();
503         if (it->closed()) {
504             segmentCount += 1;
505         }
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("                CubicCurveTo {\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     }
587     if (cmaxx > maxx) {
588         maxx = cmaxx;
589     }
590     if (cminy < miny) {
591         miny = cminy;
592     }
593     if (cmaxy > maxy) {
594         maxy = cmaxy;
595     }
597     return true;
602 #else
604 /**
605  *  Output the curve data to buffer
606  */
607 bool JavaFXOutput::doCurve(SPItem *item, const String &id)
609     using Geom::X;
610     using Geom::Y;
612     //### Get the Shape
613     if (!SP_IS_SHAPE(item)) { //Bulia's suggestion.  Allow all shapes
614         return true;
615     }
617     SPShape *shape = SP_SHAPE(item);
618     SPCurve *curve = shape->curve;
619     if (curve->is_empty()) {
620         return true;
621     }
623     nrShapes++;
625     out("        SVGPath \n");
626     out("        {\n");
627     out("        id: \"%s\"\n", id.c_str());
629     /**
630      * Output the style information
631      */
632     if (!doStyle(SP_OBJECT_STYLE(shape))) {
633         return false;
634     }
636     // convert the path to only lineto's and cubic curveto's:
637     Geom::Scale yflip(1.0, -1.0);
638     Geom::Matrix tf = sp_item_i2d_affine(item) * yflip;
639     Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );
641     //Count the NR_CURVETOs/LINETOs (including closing line segment)
642     nrNodes = 0;
643     for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {
644         nrNodes += (*it).size();
645         if (it->closed()) {
646             nrNodes += 1;
647         }
648     }
650     char *dataStr = sp_svg_write_path(pathv);
651     out("        content: \"%s\"\n", dataStr);
652     free(dataStr);
654     Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() );
656     /**
657      * Get the Min and Max X and Y extends for the Path.
658      * ....For all Subpaths in the <path>
659      */
660     for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)
661         {
662         cminmax.expandTo(pit->front().initialPoint());
663         /**
664          * For all segments in the subpath
665          */
666         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
667             {
668             cminmax.expandTo(cit->finalPoint());
669             }
670         }
672     out("        },\n");
674     double cminx = cminmax.min()[X];
675     double cmaxx = cminmax.max()[X];
676     double cminy = cminmax.min()[Y];
677     double cmaxy = cminmax.max()[Y];
679     if (cminx < minx) {
680         minx = cminx;
681     }
682     if (cmaxx > maxx) {
683         maxx = cmaxx;
684     }
685     if (cminy < miny) {
686         miny = cminy;
687     }
688     if (cmaxy > maxy) {
689         maxy = cmaxy;
690     }
692     return true;
697 #endif  /* #if o */
701 /**
702  *  Output the tree data to buffer
703  */
704 bool JavaFXOutput::doTreeRecursive(SPDocument *doc, SPObject *obj)
706     /**
707      * Check the type of node and process
708      */
709     String id;
710     if (!obj->getId())
711         {
712         char buf[16];
713         sprintf(buf, "id%d", idindex++);
714         id = buf;
715         }
716     else
717         {
718             id = obj->getId();
719         }
720     if (SP_IS_ITEM(obj))
721         {
722         SPItem *item = SP_ITEM(obj);
723         if (!doCurve(item, id)) {
724             return false;
725         }
726         }
727     else if (SP_IS_GRADIENT(obj))
728         {
729         SPGradient *grad = SP_GRADIENT(obj);
730         if (!doGradient(grad, id)) {
731             return false;
732         }
733         }
735     /**
736      * Descend into children
737      */
738     for (SPObject *child = obj->firstChild() ; child ; child = child->next)
739         {
740             if (!doTreeRecursive(doc, child)) {
741                 return false;
742             }
743         }
745     return true;
749 /**
750  *  Output the curve data to buffer
751  */
752 bool JavaFXOutput::doTree(SPDocument *doc)
755     double bignum = 1000000.0;
756     minx  =  bignum;
757     maxx  = -bignum;
758     miny  =  bignum;
759     maxy  = -bignum;
761     if (!doTreeRecursive(doc, doc->root)) {
762         return false;
763     }
765     return true;
770 bool JavaFXOutput::doBody(SPDocument *doc, SPObject *obj)
772     /**
773      * Check the type of node and process
774      */
775     String id;
776     if (!obj->getId())
777         {
778         char buf[16];
779         sprintf(buf, "id%d", idindex++);
780         id = buf;
781         }
782     else
783         {
784             id = obj->getId();
785         }
787     if (SP_IS_ITEM(obj)) {
788         SPItem *item = SP_ITEM(obj);
789         //### Get the Shape
790         if (SP_IS_SHAPE(item)) {//Bulia's suggestion.  Allow all shapes
791             SPShape *shape = SP_SHAPE(item);
792             SPCurve *curve = shape->curve;
793             if (!curve->is_empty()) {
794                 String jfxid = sanatize(id);
795                 out("               %s(),\n", jfxid.c_str());
796             }
797         }
798     }
799     else if (SP_IS_GRADIENT(obj)) {
800         //TODO: what to do with Gradient within body?????
801         //SPGradient *grad = SP_GRADIENT(reprobj);
802         //if (!doGradient(grad, id)) {
803         //    return false;
804         //}
805     }
807     /**
808      * Descend into children
809      */
810     for (SPObject *child = obj->firstChild() ; child ; child = child->next)
811         {
812             if (!doBody(doc, child)) {
813                 return false;
814             }
815         }
817     return true;
822 //########################################################################
823 //# M A I N    O U T P U T
824 //########################################################################
828 /**
829  *  Set values back to initial state
830  */
831 void JavaFXOutput::reset()
833     nrNodes    = 0;
834     nrShapes   = 0;
835     idindex    = 0;
836     name.clear();
837     outbuf.clear();
838     foutbuf.clear();
843 /**
844  * Saves the <paths> of an Inkscape SVG file as JavaFX spline definitions
845  */
846 bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)
848     reset();
851     name = Glib::path_get_basename(filename_utf8);
852     int pos = name.find('.');
853     if (pos > 0) {
854         name = name.substr(0, pos);
855     }
858     //###### SAVE IN JAVAFX FORMAT TO BUFFER
859     //# Lets do the curves first, to get the stats
861     if (!doTree(doc)) {
862         return false;
863     }
864     String curveBuf = outbuf;
865     outbuf.clear();
867     if (!doHeader()) {
868         return false;
869     }
871     outbuf.append(curveBuf);
873     out("   override function create(): Node {\n");
874     out("       Group {\n");
875     out("           content: [\n");
876     idindex    = 0;
878     doBody(doc, doc->root);
880     if (!doTail()) {
881         return false;
882     }
886     //###### WRITE TO FILE
887     FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");
888     if (!f)
889         {
890         err("Could open JavaFX file '%s' for writing", filename_utf8);
891         return false;
892         }
894     for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); iter++)
895         {
896         fputc(*iter, f);
897         }
899     fclose(f);
901     return true;
907 //########################################################################
908 //# EXTENSION API
909 //########################################################################
913 #include "clear-n_.h"
917 /**
918  * API call to save document
919 */
920 void
921 JavaFXOutput::save(Inkscape::Extension::Output */*mod*/,
922                         SPDocument *doc, gchar const *filename_utf8)
924     /* N.B. The name `filename_utf8' represents the fact that we want it to be in utf8; whereas in
925      * fact we know that some callers of Extension::save pass something in the filesystem's
926      * encoding, while others do g_filename_to_utf8 before calling.
927      *
928      * In terms of safety, it's best to make all callers pass actual filenames, since in general
929      * one can't round-trip from filename to utf8 back to the same filename.  Whereas the argument
930      * for passing utf8 filenames is one of convenience: we often want to pass to g_warning or
931      * store as a string (rather than a byte stream) in XML, or the like. */
932     if (!saveDocument(doc, filename_utf8))
933         {
934         g_warning("Could not save JavaFX file '%s'", filename_utf8);
935         }
940 /**
941  * Make sure that we are in the database
942  */
943 bool JavaFXOutput::check (Inkscape::Extension::Extension */*module*/)
945     /* We don't need a Key
946     if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_JFX)) {
947         return FALSE;
948     }
949     */
951     return true;
956 /**
957  * This is the definition of JavaFX output.  This function just
958  * calls the extension system with the memory allocated XML that
959  * describes the data.
960 */
961 void
962 JavaFXOutput::init()
964     Inkscape::Extension::build_from_mem(
965         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
966             "<name>" N_("JavaFX Output") "</name>\n"
967             "<id>org.inkscape.output.jfx</id>\n"
968             "<output>\n"
969                 "<extension>.fx</extension>\n"
970                 "<mimetype>text/x-javafx-script</mimetype>\n"
971                 "<filetypename>" N_("JavaFX (*.fx)") "</filetypename>\n"
972                 "<filetypetooltip>" N_("JavaFX Raytracer File") "</filetypetooltip>\n"
973             "</output>\n"
974         "</inkscape-extension>",
975         new JavaFXOutput());
982 }  // namespace Internal
983 }  // namespace Extension
984 }  // namespace Inkscape
987 /*
988   Local Variables:
989   mode:c++
990   c-file-style:"stroustrup"
991   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
992   indent-tabs-mode:nil
993   fill-column:99
994   End:
995 */
996 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :