如何将JavaFX节点导出到SVG图像?

时间:2012-09-25 15:48:54

标签: java svg javafx vector-graphics

换句话说,我正在尝试像Java Batik allows you to do with Swing.

那样使用JavaFX

我希望能够在我的JavaFX UI中捕获任意节点的外观,就像Node.snapshot()一样,除了我需要像SVG这样的矢量格式的图像,而不是光栅图像。 (并且将我的节点的光栅快照插入到SVG图像中是不够的;它需要是一个适当的,可缩放的矢量图像。)

这是一个长期项目,所以我甚至愿意实现我自己的GraphicsContext,或者JavaFX的保留模式API中的等价物。

有没有人知道是否有办法做到这一点?我希望在JavaFX中甚至可以做什么?

4 个答案:

答案 0 :(得分:5)

我开始编写一个JavaFx节点到SVG转换器,"扩展" Gerrit Grunwald的ShapeConverter只转换Shape几何形状:

https://github.com/stefaneidelloth/JavaFxNodeToSvg

......并在一定程度的挫败之后停止了它。

请随时改进,添加功能并修复错误。

转换器适用于简单的Node示例,但对于图表等高级示例则失败。我失败的转换器可能会为您提供一个起点。下面的图说明了当前的状态。左侧显示原始JavaFx节点,右侧显示结果svg输出。

简单节点示例(有效): enter image description here

图表示例(不起作用): enter image description here

这里有相应的svg文件:

https://github.com/stefaneidelloth/JavaFxNodeToSvg/tree/master/output

进一步说明

除了上面的图表示例所示的定位问题之外,还需要考虑其他一些问题:

JavaFx提供比SVG标准元素更多的css功能。例如,(矩形)JavaFx区域可以为四条边界线中的每一条具有单独的线条样式。这样的区域不能简单地转换为SVG矩形。相反,需要单独绘制区域的四条边界线。此外,这种边界线的每个末端可以具有两个单独的边缘半径:垂直半径和水平半径。为了转换"四"边界线到相应的SVG线......可能需要进一步分割边界线:为四条边界线中的每一条绘制两个圆角部分和一个直线部分。因此,在某些情况下,可能有12个SVG路径元素来绘制单个JavaFx区域的边框。此外,Region的背景填充可以具有与Region的边界不同的半径。绘制Region的背景可能需要更多的SVG元素。因此,即使转换了矩形区域&#​​34;会变得相当复杂。

请注意,JavaFx节点可能已设置动画。例如,行的不透明度在开始时为0,在几毫秒后逐渐消失为另一个值。

FadeTransition ft = new FadeTransition(Duration.millis(250), borderline);
                    ft.setToValue(0);                       
                    ft.play();

因此,仅转换禁用动画的节点或等待节点处于稳定状态才有意义。

如果JavaFx图表的转换工作一天,我会非常高兴,因此我可以在我的一个项目中使用JavaFx绘图和SVG导出。

我决定暂时停止转换器的开发,并使用JavaScript库(d3)调查绘图和SVG导出。如果该策略更糟糕,我可能会回到JavaFxNodeToSvgConverter。

修改 使用d3.js进行绘图非常有效,我决定不使用JavaFx来绘制/ svg创建。 https://github.com/stefaneidelloth/javafx-d3

答案 1 :(得分:1)

有一个简单的JavaFX shape to SVG string converter,它只会在没有应用css的情况下转换基本形状,而不是任意节点,但也许这可能只是你需要的。

答案 2 :(得分:1)

JFX JIRA中有一个开放的错误请求

https://javafx-jira.kenai.com/browse/RT-38559

(需要注册;然后您可以投票支持该问题)。它目前说

  

考虑将来的版本。

并标记为版本9.

答案 3 :(得分:0)

我们的想法是,如果您能够将JavaFX节点树结构转换为一系列Graphics2D订单,那么您可以使用具有Graphics2D驱动程序的Batik。

问题在于,将JavaFX树结构转换为Graphics2D顺序并不像您想象的那么困难(即使您处理节点的CSS属性)。

有些读者建议我应该包含一些代码,而不仅仅是图书馆的链接及其工作的图片。这样做并不容易,因为即使它不是那么难做,它仍然有5000行代码。

如何执行转换:

  • 你必须有一个Graphics2D才能转换为SVG(例如Batik SVGGraphics2D类);
  • 遍历JavaFX结构;
  • 对于结构中的每个节点,首先将此节点上的当前javaFX转换转换为AffineTransform,并将转换应用于节点(您必须在堆栈中执行此操作,以确保在最后恢复为初始AffineTransform节点);
  • 并且对于每个节点,您必须转换为适当的Graphics2D订单。

请注意,您不需要支持很多Node类型,主要是:

  • 区域(控件是可以具有关联图形的特殊区域类型)
  • 形状(文字,矩形等......)
  • ImageView for images

您可能还需要处理节点剪辑以在Graphics2D中应用关联的剪辑。

此外,您还必须处理Node的CSS属性。

尽管如此,我使用的库(这个算法适用于此算法)在这里:http://sourceforge.net/projects/jfxconverter/