Code

Merge and cleanup of GSoC C++-ification project.
[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  *   Abhishek Sharma
13  *
14  * Copyright (C) 2008,2009 Authors
15  *
16  * Released under GNU GPL, read the file 'COPYING' for more information
17  */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 #include "javafx-out.h"
24 #include <inkscape.h>
25 #include <inkscape-version.h>
26 #include <sp-path.h>
27 #include <sp-linear-gradient.h>
28 #include <sp-radial-gradient.h>
29 #include <style.h>
30 #include <display/curve.h>
31 #include <display/canvas-bpath.h>
32 #include <svg/svg.h>
33 #include <extension/system.h>
34 #include <2geom/pathvector.h>
35 #include <2geom/rect.h>
36 #include <2geom/bezier-curve.h>
37 #include <2geom/hvlinesegment.h>
38 #include "helper/geom.h"
39 #include "helper/geom-curves.h"
40 #include <io/sys.h>
43 #include <string>
44 #include <stdio.h>
45 #include <stdarg.h>
48 namespace Inkscape
49 {
50 namespace Extension
51 {
52 namespace Internal
53 {
58 //########################################################################
59 //# M E S S A G E S
60 //########################################################################
62 static void err(const char *fmt, ...)
63 {
64     va_list args;
65     g_log(NULL,  G_LOG_LEVEL_WARNING, "javafx-out err: ");
66     va_start(args, fmt);
67     g_logv(NULL, G_LOG_LEVEL_WARNING, fmt, args);
68     va_end(args);
69     g_log(NULL,  G_LOG_LEVEL_WARNING, "\n");
70 }
73 //########################################################################
74 //# U T I L I T Y
75 //########################################################################
77 /**
78  * Got this method from Bulia, and modified it a bit.  It basically
79  * starts with this style, gets its SPObject parent, walks up the object
80  * tree and finds all of the opacities and multiplies them.
81  *
82  * We use this for our "flat" object output.  If the code is modified
83  * to reflect a tree of <groups>, then this will be unneccessary.
84  */
85 static double effective_opacity(const SPStyle *style)
86 {
87     double val = 1.0;
88     for (SPObject const *obj = style->object; obj ; obj = obj->parent)
89         {
90         style = SP_OBJECT_STYLE(obj);
91         if (style) {
92             val *= SP_SCALE24_TO_FLOAT(style->opacity.value);
93         }
94         }
95     return val;
96 }
98 //########################################################################
99 //# OUTPUT FORMATTING
100 //########################################################################
103 /**
104  * We want to control floating output format.
105  * Especially to avoid localization. (decimal ',' for example)
106  */
107 static JavaFXOutput::String dstr(double d)
109     char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
110     g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
111                   "%.8f", (gdouble)d);
112     JavaFXOutput::String s = dbuf;
113     return s;
116 #define DSTR(d) (dstr(d).c_str())
119 /**
120  * Format a double as an integer
121  */
122 static JavaFXOutput::String istr(double d)
124     char dbuf[G_ASCII_DTOSTR_BUF_SIZE+1];
125     g_ascii_formatd(dbuf, G_ASCII_DTOSTR_BUF_SIZE,
126                   "%.0f", (gdouble)d);
127     JavaFXOutput::String s = dbuf;
128     return s;
131 #define ISTR(d) (istr(d).c_str())
134 /**
135  * Format an rgba() string
136  */
137 static JavaFXOutput::String rgba(guint32 rgba)
139     unsigned int r = SP_RGBA32_R_U(rgba);
140     unsigned int g = SP_RGBA32_G_U(rgba);
141     unsigned int b = SP_RGBA32_B_U(rgba);
142     unsigned int a = SP_RGBA32_A_U(rgba);
143     char buf[80];
144     snprintf(buf, 79, "Color.rgb(0x%02x, 0x%02x, 0x%02x, %s)",
145                            r, g, b, DSTR((double)a/255.0));
146     JavaFXOutput::String s = buf;
147     return s;
151 /**
152  * Format an rgba() string for a color and a 0.0-1.0 alpha
153  */
154 static JavaFXOutput::String rgba(SPColor color, gdouble alpha)
156     return rgba(color.toRGBA32(alpha));
159 /**
160  * Map Inkscape linecap styles to JavaFX
161  */
162 static JavaFXOutput::String getStrokeLineCap(unsigned value) {
163     switch(value) {
164         case SP_STROKE_LINECAP_BUTT:
165             return "StrokeLineCap.BUTT";
166         case SP_STROKE_LINECAP_ROUND:
167             return "StrokeLineCap.ROUND";
168         case SP_STROKE_LINECAP_SQUARE:
169             return "StrokeLineCap.SQUARE";
170         default:
171             return "INVALID LINE CAP";
172     }
176 /**
177  * Map Inkscape linejoin styles to JavaFX
178  */
179 static JavaFXOutput::String getStrokeLineJoin(unsigned value) {
180     switch(value) {
181         case SP_STROKE_LINEJOIN_MITER:
182             return "StrokeLineJoin.MITER";
183         case SP_STROKE_LINEJOIN_ROUND:
184             return "StrokeLineJoin.ROUND";
185         case SP_STROKE_LINEJOIN_BEVEL:
186             return "StrokeLineJoin.BEVEL";
187         default:
188             return "INVALID LINE JOIN";
189     }
193 /**
194  * Replace illegal characters for JavaFX for a underscore.
195  */
196 static JavaFXOutput::String sanatize(const JavaFXOutput::String &badstr){
197     JavaFXOutput::String good(badstr);
198     for (int pos = 0; pos < static_cast<int>(badstr.length()); ++pos )
199         if ((badstr.at(pos)=='-')||(badstr.at(pos)==' ')) {
200             good.replace(pos, 1, "_");
201         }
202     return good;
205 /**
206  *  Output data to the buffer, printf()-style
207  */
208 void JavaFXOutput::out(const char *fmt, ...)
210     va_list args;
211     va_start(args, fmt);
212     gchar *output = g_strdup_vprintf(fmt, args);
213     va_end(args);
214     outbuf.append(output);
215     g_free(output);
220 /**
221  * Output the file header
222  */
223 bool JavaFXOutput::doHeader()
225     time_t tim = time(NULL);
226     out("/*###################################################################\n");
227     out("### This JavaFX document was generated by Inkscape\n");
228     out("### http://www.inkscape.org\n");
229     out("### Created: %s",   ctime(&tim));
230     out("### Version: %s\n", Inkscape::version_string);
231     out("#####################################################################\n");
232     out("### NOTES:\n");
233     out("### ============\n");
234     out("### JavaFX information can be found at\n");
235     out("### http://www.javafx.com/\n");
236     out("###\n");
237     out("### If you have any problems with this output, please see the\n");
238     out("### Inkscape project at http://www.inkscape.org, or visit\n");
239     out("### the #inkscape channel on irc.freenode.net . \n");
240     out("###\n");
241     out("###################################################################*/\n");
242     out("\n\n");
243     out("/*###################################################################\n");
244     out("##   Exports in this file\n");
245     out("##==========================\n");
246     out("##    Shapes   : %d\n", nrShapes);
247     out("##    Nodes    : %d\n", nrNodes);
248     out("###################################################################*/\n");
249     out("\n\n");
251     // import javafx libraries we can need
252     out("import javafx.scene.*;\n");
253     out("import javafx.scene.shape.*;\n");
254     out("import javafx.scene.transform.*;\n");
255     out("import javafx.scene.paint.*;\n");
256     out("\n");
258     out("\n\n");
260     // Creates a class extended from CustomNode
261     out("public class %s extends CustomNode {\n", name.c_str());
263     return true;
268 /**
269  *  Output the file footer
270  */
271 bool JavaFXOutput::doTail()
273     float border = 25.0;
275     // Write the tail of CustomNode
276     out("           ] // content\n");
277     out("           transforms: Translate { x : %s, y : %s }\n",
278         DSTR((-minx) + border), DSTR((-miny) + border) );
279     out("       } // Group\n");
280     out("   } // function create()\n");
281     out("} // class %s\n", name.c_str());
282     out("\n");
284     // Stage
285 //     out("    stage: Stage {\n");
286 //     out("        content: %s{}\n", name.c_str());
287 //     out("    } // Stage\n");
290     out("\n");
292     out("/*###################################################################\n");
293     out("### E N D   C L A S S    %s\n", name.c_str());
294     out("###################################################################*/\n");
295     out("\n\n");
296     return true;
301 /**
302  *  Output gradient information to the buffer
303  */
304 bool JavaFXOutput::doGradient(SPGradient *grad, const String &id)
306     String jfxid = sanatize(id);
308     if (SP_IS_LINEARGRADIENT(grad))
309         {
310         SPLinearGradient *g = SP_LINEARGRADIENT(grad);
311         out("    /* create LinearGradient for %s */\n", jfxid.c_str());
312         out("    function %s(): LinearGradient {\n",  jfxid.c_str());
313         out("        LinearGradient {\n");
314         std::vector<SPGradientStop> stops = g->vector.stops;
315         if (stops.size() > 0)
316             {
317             out("            stops:\n");
318             out("                [\n");
319             for (unsigned int i = 0 ; i<stops.size() ; i++)
320                 {
321                 SPGradientStop stop = stops[i];
322                 out("                Stop {\n");
323                 out("                    offset: %s\n", DSTR(stop.offset));
324                 out("                    color: %s\n",  rgba(stop.color, stop.opacity).c_str());
325                 out("                },\n");
326                 }
327             out("            ]\n");
328             }
329         out("        };\n");
330         out("    } // end LinearGradient: %s\n", jfxid.c_str());
331         out("\n\n");
332         }
333     else if (SP_IS_RADIALGRADIENT(grad))
334         {
335         SPRadialGradient *g = SP_RADIALGRADIENT(grad);
336         out("    /* create RadialGradient for %s */\n", jfxid.c_str());
337         out("    function %s() {\n", jfxid.c_str());
338         out("        RadialGradient {\n");
339         out("            centerX: %s\n", DSTR(g->cx.value));
340         out("            centerY: %s\n", DSTR(g->cy.value));
341         out("            focusX: %s\n",  DSTR(g->fx.value));
342         out("            focusY: %s\n",  DSTR(g->fy.value));
343         out("            radius: %s\n",  DSTR(g->r.value ));
344         std::vector<SPGradientStop> stops = g->vector.stops;
345         if (stops.size() > 0)
346             {
347             out("            stops:\n");
348             out("            [\n");
349             for (unsigned int i = 0 ; i<stops.size() ; i++)
350                 {
351                 SPGradientStop stop = stops[i];
352                 out("                Stop {\n");
353                 out("                    offset: %s\n", DSTR(stop.offset));
354                 out("                    color: %s\n",  rgba(stop.color, stop.opacity).c_str());
355                 out("                },\n");
356                 }
357             out("            ]\n");
358             }
359         out("        };\n");
360         out("    } // end RadialGradient: %s\n", jfxid.c_str());
361         out("\n\n");
362         }
363     else
364         {
365         err("Unknown gradient type for '%s'\n", jfxid.c_str());
366         return false;
367         }
370     return true;
376 /**
377  *  Output an element's style attribute
378  */
379 bool JavaFXOutput::doStyle(SPStyle *style)
381     if (!style) {
382         return true;
383     }
385     out("            opacity: %s\n", DSTR(effective_opacity(style)));
387     /**
388      * Fill
389      */
390     SPIPaint const &fill = style->fill;
391     if (fill.isColor())
392         {
393         // see color.h for how to parse SPColor
394         out("            fill: %s\n",
395             rgba(fill.value.color, SP_SCALE24_TO_FLOAT(style->fill_opacity.value)).c_str());
396         }
397     else if (fill.isPaintserver()){
398         if (fill.value.href && fill.value.href->getURI() ){
399             String uri = fill.value.href->getURI()->toString();
400             /* trim the anchor '#' from the front */
401             if (uri.size() > 0 && uri[0]=='#') {
402                 uri = uri.substr(1);
403             }
404             out("            fill: %s()\n", sanatize(uri).c_str());
405         }
406     }
409     /**
410      * Stroke
411      */
412     /**
413      *NOTE:  Things in style we can use:
414      * SPIPaint stroke;
415      * SPILength stroke_width;
416      * SPIEnum stroke_linecap;
417      * SPIEnum stroke_linejoin;
418      * SPIFloat stroke_miterlimit;
419      * NRVpathDash stroke_dash;
420      * unsigned stroke_dasharray_set : 1;
421      * unsigned stroke_dasharray_inherit : 1;
422      * unsigned stroke_dashoffset_set : 1;
423      * SPIScale24 stroke_opacity;
424      */
425     if (style->stroke_opacity.value > 0)
426         {
427         SPIPaint const &stroke = style->stroke;
428         out("            stroke: %s\n",
429             rgba(stroke.value.color, SP_SCALE24_TO_FLOAT(style->stroke_opacity.value)).c_str());
430         double strokewidth = style->stroke_width.value;
431         unsigned linecap   = style->stroke_linecap.value;
432         unsigned linejoin  = style->stroke_linejoin.value;
433         out("            strokeWidth: %s\n",      DSTR(strokewidth));
434         out("            strokeLineCap: %s\n",    getStrokeLineCap(linecap).c_str());
435         out("            strokeLineJoin: %s\n",   getStrokeLineJoin(linejoin).c_str());
436         out("            strokeMiterLimit: %s\n", DSTR(style->stroke_miterlimit.value));
437         if (style->stroke_dasharray_set) {
438            if (style->stroke_dashoffset_set) {
439                out("            strokeDashOffset: %s\n", DSTR(style->stroke_dash.offset));
440            }
441            out("            strokeDashArray: [ ");
442            for(int i = 0; i < style->stroke_dash.n_dash; i++ ) {
443                if (i > 0) {
444                    out(", %.2lf", style->stroke_dash.dash[i]);
445                }else {
446                    out(" %.2lf", style->stroke_dash.dash[i]);
447                }
448            }
449            out(" ]\n");
450         }
452         }
454     return true;
458 #if 1
460 /**
461  *  Output the curve data to buffer
462  */
463 bool JavaFXOutput::doCurve(SPItem *item, const String &id)
465     using Geom::X;
466     using Geom::Y;
468     String jfxid = sanatize(id);
470     //### Get the Shape
471     if (!SP_IS_SHAPE(item)) { //Bulia's suggestion.  Allow all shapes
472         return true;
473     }
475     SPShape *shape = SP_SHAPE(item);
476     SPCurve *curve = shape->curve;
477     if (curve->is_empty()) {
478         return true;
479     }
481     nrShapes++;
483     out("    /** path %s */\n", jfxid.c_str());
484     out("    function %s() : Path {\n",jfxid.c_str());
485     out("        Path {\n");
486     out("            id: \"%s\"\n", jfxid.c_str());
488     /**
489      * Output the style information
490      */
491     if (!doStyle(SP_OBJECT_STYLE(shape))) {
492         return false;
493     }
495     // convert the path to only lineto's and cubic curveto's:
496     Geom::Scale yflip(1.0, -1.0);
497     Geom::Matrix tf = item->i2d_affine() * 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         }
507     }
509     out("            elements: [\n");
511     unsigned int segmentNr = 0;
513     nrNodes += segmentCount;
515     Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() );
517     /**
518      * For all Subpaths in the <path>
519      */
520     for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)
521         {
522         Geom::Point p = pit->front().initialPoint();
523         cminmax.expandTo(p);
524         out("                MoveTo {\n");
525         out("                    x: %s\n", DSTR(p[X]));
526         out("                    y: %s\n", DSTR(p[Y]));
527         out("                },\n");
529         /**
530          * For all segments in the subpath
531          */
532         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
533             {
534             //### LINE
535             if ( dynamic_cast<Geom::LineSegment  const *> (&*cit) ||
536                 dynamic_cast<Geom::HLineSegment const *> (&*cit) ||
537                 dynamic_cast<Geom::VLineSegment const *> (&*cit) )
538                 {
539                 Geom::Point p = cit->finalPoint();
540                 out("                LineTo {\n");
541                 out("                    x: %s\n", DSTR(p[X]));
542                 out("                    y: %s\n", DSTR(p[Y]));
543                 out("                },\n");
544                 nrNodes++;
545                 }
546             //### BEZIER
547             else if (Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const*>(&*cit))
548                 {
549                 std::vector<Geom::Point> points = cubic->points();
550                 Geom::Point p1 = points[1];
551                 Geom::Point p2 = points[2];
552                 Geom::Point p3 = points[3];
553                 out("                CubicCurveTo {\n");
554                 out("                    controlX1: %s\n", DSTR(p1[X]));
555                 out("                    controlY1: %s\n", DSTR(p1[Y]));
556                 out("                    controlX2: %s\n", DSTR(p2[X]));
557                 out("                    controlY2: %s\n", DSTR(p2[Y]));
558                 out("                    x: %s\n",         DSTR(p3[X]));
559                 out("                    y: %s\n",         DSTR(p3[Y]));
560                 out("                },\n");
561                 nrNodes++;
562                 }
563             else
564                 {
565                 g_error ("logical error, because pathv_to_linear_and_cubic_beziers was used");
566                 }
567             segmentNr++;
568             cminmax.expandTo(cit->finalPoint());
569             }
570         if (pit->closed())
571             {
572             out("                ClosePath {},\n");
573             }
574         }
576     out("            ] // elements\n");
577     out("        }; // Path\n");
578     out("    } // end path %s\n\n", jfxid.c_str());
580     double cminx = cminmax.min()[X];
581     double cmaxx = cminmax.max()[X];
582     double cminy = cminmax.min()[Y];
583     double cmaxy = cminmax.max()[Y];
585     if (cminx < minx) {
586         minx = cminx;
587     }
588     if (cmaxx > maxx) {
589         maxx = cmaxx;
590     }
591     if (cminy < miny) {
592         miny = cminy;
593     }
594     if (cmaxy > maxy) {
595         maxy = cmaxy;
596     }
598     return true;
603 #else
605 /**
606  *  Output the curve data to buffer
607  */
608 bool JavaFXOutput::doCurve(SPItem *item, const String &id)
610     using Geom::X;
611     using Geom::Y;
613     //### Get the Shape
614     if (!SP_IS_SHAPE(item)) { //Bulia's suggestion.  Allow all shapes
615         return true;
616     }
618     SPShape *shape = SP_SHAPE(item);
619     SPCurve *curve = shape->curve;
620     if (curve->is_empty()) {
621         return true;
622     }
624     nrShapes++;
626     out("        SVGPath \n");
627     out("        {\n");
628     out("        id: \"%s\"\n", id.c_str());
630     /**
631      * Output the style information
632      */
633     if (!doStyle(SP_OBJECT_STYLE(shape))) {
634         return false;
635     }
637     // convert the path to only lineto's and cubic curveto's:
638     Geom::Scale yflip(1.0, -1.0);
639     Geom::Matrix tf = item->i2d_affine() * yflip;
640     Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curve->get_pathvector() * tf );
642     //Count the NR_CURVETOs/LINETOs (including closing line segment)
643     nrNodes = 0;
644     for(Geom::PathVector::const_iterator it = pathv.begin(); it != pathv.end(); ++it) {
645         nrNodes += (*it).size();
646         if (it->closed()) {
647             nrNodes += 1;
648         }
649     }
651     char *dataStr = sp_svg_write_path(pathv);
652     out("        content: \"%s\"\n", dataStr);
653     free(dataStr);
655     Geom::Rect cminmax( pathv.front().initialPoint(), pathv.front().initialPoint() );
657     /**
658      * Get the Min and Max X and Y extends for the Path.
659      * ....For all Subpaths in the <path>
660      */
661     for (Geom::PathVector::const_iterator pit = pathv.begin(); pit != pathv.end(); ++pit)
662         {
663         cminmax.expandTo(pit->front().initialPoint());
664         /**
665          * For all segments in the subpath
666          */
667         for (Geom::Path::const_iterator cit = pit->begin(); cit != pit->end_closed(); ++cit)
668             {
669             cminmax.expandTo(cit->finalPoint());
670             }
671         }
673     out("        },\n");
675     double cminx = cminmax.min()[X];
676     double cmaxx = cminmax.max()[X];
677     double cminy = cminmax.min()[Y];
678     double cmaxy = cminmax.max()[Y];
680     if (cminx < minx) {
681         minx = cminx;
682     }
683     if (cmaxx > maxx) {
684         maxx = cmaxx;
685     }
686     if (cminy < miny) {
687         miny = cminy;
688     }
689     if (cmaxy > maxy) {
690         maxy = cmaxy;
691     }
693     return true;
698 #endif  /* #if o */
702 /**
703  *  Output the tree data to buffer
704  */
705 bool JavaFXOutput::doTreeRecursive(SPDocument *doc, SPObject *obj)
707     /**
708      * Check the type of node and process
709      */
710     String id;
711     if (!obj->getId())
712         {
713         char buf[16];
714         sprintf(buf, "id%d", idindex++);
715         id = buf;
716         }
717     else
718         {
719             id = obj->getId();
720         }
721     if (SP_IS_ITEM(obj))
722         {
723         SPItem *item = SP_ITEM(obj);
724         if (!doCurve(item, id)) {
725             return false;
726         }
727         }
728     else if (SP_IS_GRADIENT(obj))
729         {
730         SPGradient *grad = SP_GRADIENT(obj);
731         if (!doGradient(grad, id)) {
732             return false;
733         }
734         }
736     /**
737      * Descend into children
738      */
739     for (SPObject *child = obj->firstChild() ; child ; child = child->next)
740         {
741             if (!doTreeRecursive(doc, child)) {
742                 return false;
743             }
744         }
746     return true;
750 /**
751  *  Output the curve data to buffer
752  */
753 bool JavaFXOutput::doTree(SPDocument *doc)
756     double bignum = 1000000.0;
757     minx  =  bignum;
758     maxx  = -bignum;
759     miny  =  bignum;
760     maxy  = -bignum;
762     if (!doTreeRecursive(doc, doc->root)) {
763         return false;
764     }
766     return true;
771 bool JavaFXOutput::doBody(SPDocument *doc, SPObject *obj)
773     /**
774      * Check the type of node and process
775      */
776     String id;
777     if (!obj->getId())
778         {
779         char buf[16];
780         sprintf(buf, "id%d", idindex++);
781         id = buf;
782         }
783     else
784         {
785             id = obj->getId();
786         }
788     if (SP_IS_ITEM(obj)) {
789         SPItem *item = SP_ITEM(obj);
790         //### Get the Shape
791         if (SP_IS_SHAPE(item)) {//Bulia's suggestion.  Allow all shapes
792             SPShape *shape = SP_SHAPE(item);
793             SPCurve *curve = shape->curve;
794             if (!curve->is_empty()) {
795                 String jfxid = sanatize(id);
796                 out("               %s(),\n", jfxid.c_str());
797             }
798         }
799     }
800     else if (SP_IS_GRADIENT(obj)) {
801         //TODO: what to do with Gradient within body?????
802         //SPGradient *grad = SP_GRADIENT(reprobj);
803         //if (!doGradient(grad, id)) {
804         //    return false;
805         //}
806     }
808     /**
809      * Descend into children
810      */
811     for (SPObject *child = obj->firstChild() ; child ; child = child->next)
812         {
813             if (!doBody(doc, child)) {
814                 return false;
815             }
816         }
818     return true;
823 //########################################################################
824 //# M A I N    O U T P U T
825 //########################################################################
829 /**
830  *  Set values back to initial state
831  */
832 void JavaFXOutput::reset()
834     nrNodes    = 0;
835     nrShapes   = 0;
836     idindex    = 0;
837     name.clear();
838     outbuf.clear();
839     foutbuf.clear();
844 /**
845  * Saves the <paths> of an Inkscape SVG file as JavaFX spline definitions
846  */
847 bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8)
849     reset();
852     name = Glib::path_get_basename(filename_utf8);
853     int pos = name.find('.');
854     if (pos > 0) {
855         name = name.substr(0, pos);
856     }
859     //###### SAVE IN JAVAFX FORMAT TO BUFFER
860     //# Lets do the curves first, to get the stats
862     if (!doTree(doc)) {
863         return false;
864     }
865     String curveBuf = outbuf;
866     outbuf.clear();
868     if (!doHeader()) {
869         return false;
870     }
872     outbuf.append(curveBuf);
874     out("   override function create(): Node {\n");
875     out("       Group {\n");
876     out("           content: [\n");
877     idindex    = 0;
879     doBody(doc, doc->root);
881     if (!doTail()) {
882         return false;
883     }
887     //###### WRITE TO FILE
888     FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w");
889     if (!f)
890         {
891         err("Could open JavaFX file '%s' for writing", filename_utf8);
892         return false;
893         }
895     for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); iter++)
896         {
897         fputc(*iter, f);
898         }
900     fclose(f);
902     return true;
908 //########################################################################
909 //# EXTENSION API
910 //########################################################################
914 #include "clear-n_.h"
918 /**
919  * API call to save document
920 */
921 void
922 JavaFXOutput::save(Inkscape::Extension::Output */*mod*/,
923                         SPDocument *doc, gchar const *filename_utf8)
925     /* N.B. The name `filename_utf8' represents the fact that we want it to be in utf8; whereas in
926      * fact we know that some callers of Extension::save pass something in the filesystem's
927      * encoding, while others do g_filename_to_utf8 before calling.
928      *
929      * In terms of safety, it's best to make all callers pass actual filenames, since in general
930      * one can't round-trip from filename to utf8 back to the same filename.  Whereas the argument
931      * for passing utf8 filenames is one of convenience: we often want to pass to g_warning or
932      * store as a string (rather than a byte stream) in XML, or the like. */
933     if (!saveDocument(doc, filename_utf8))
934         {
935         g_warning("Could not save JavaFX file '%s'", filename_utf8);
936         }
941 /**
942  * Make sure that we are in the database
943  */
944 bool JavaFXOutput::check (Inkscape::Extension::Extension */*module*/)
946     /* We don't need a Key
947     if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_JFX)) {
948         return FALSE;
949     }
950     */
952     return true;
957 /**
958  * This is the definition of JavaFX output.  This function just
959  * calls the extension system with the memory allocated XML that
960  * describes the data.
961 */
962 void
963 JavaFXOutput::init()
965     Inkscape::Extension::build_from_mem(
966         "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n"
967             "<name>" N_("JavaFX Output") "</name>\n"
968             "<id>org.inkscape.output.jfx</id>\n"
969             "<output>\n"
970                 "<extension>.fx</extension>\n"
971                 "<mimetype>text/x-javafx-script</mimetype>\n"
972                 "<filetypename>" N_("JavaFX (*.fx)") "</filetypename>\n"
973                 "<filetypetooltip>" N_("JavaFX Raytracer File") "</filetypetooltip>\n"
974             "</output>\n"
975         "</inkscape-extension>",
976         new JavaFXOutput());
983 }  // namespace Internal
984 }  // namespace Extension
985 }  // namespace Inkscape
988 /*
989   Local Variables:
990   mode:c++
991   c-file-style:"stroustrup"
992   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
993   indent-tabs-mode:nil
994   fill-column:99
995   End:
996 */
997 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :