13

换句话说,我正在尝试用 JavaFX 做一些事情,就像Batik 允许你用 Swing 做的那样。

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

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

有谁知道是否有办法做到这一点?我希望在 JavaFX 中做的事情甚至可能吗?

4

5 回答 5

5

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

https://github.com/stefanidelloth/JavaFxNodeToSvg

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

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

该转换器适用于简单的节点示例,但不适用于图表等高级示例。我失败的转换器可能会作为您的起点。当前状态如下图所示。左侧显示原始 JavaFx 节点,右侧显示生成的 svg 输出。

简单节点示例(有效): 在此处输入图像描述

图表示例(不起作用): 在此处输入图像描述

相应的 svg 文件可在此处获得:

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

一些进一步的说明

除了上面图表示例说明的定位问题外,还必须考虑一些进一步的问题:

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

另请注意,JavaFx 节点可能是动画的。例如,一条线的不透明度在开始时为 0,并在几毫秒后淡化为另一个值。

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

因此,只有在禁用动画或等到节点处于稳定状态时才转换节点才有意义。

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

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

编辑 d3.js 的绘图效果很好,我决定不使用 JavaFx 来创建绘图/svg。 https://github.com/stefanidelloth/javafx-d3

于 2015-09-09T18:22:40.453 回答
1

JFX JIRA 中有一个未解决的错误请求,位于

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

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

考虑将来的版本。

并标记为版本 9。

于 2015-02-06T10:40:13.793 回答
1

有一个简单的JavaFX 形状到 SVG 字符串转换器,它只会在没有应用 css 的情况下转换基本形状,而不是任意节点,但这可能就是你所需要的。

于 2012-12-04T10:52:56.473 回答
0

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

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

一些读者建议我应该包含一些代码,而不仅仅是库的链接和它工作的图片。做起来没那么容易,因为就算做起来没那么难,也还是有5000行代码。

如何执行转换:

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

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

  • 区域(控件是一种特殊类型的区域,可以具有关联的图形)
  • 团体
  • 形状(文本、矩形等...)
  • 图像的 ImageView

您可能还需要注意节点剪辑以在 Graphics2D 中应用相关的剪辑。

此外,您还必须注意 Node.js 的 CSS 属性。

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

于 2016-04-19T22:07:02.510 回答
-1

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

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

您应该从一个新的空 SVGDocument 创建一个 SVGGraphics2D,例如:

Document doc = SVGDOMImplementation.getDOMImplementation().createDocument(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg", null);
SVGGraphics2D g2D = new SVGGraphics2D(doc);

然后得到要转换的Scene的根节点,对于这个节点,得到Node的类型,可以是Shape、Control、Region、ImageView、Group、SubScene、Shape3D

根据每个节点,您可以获得节点的特征。例如,对于一个形状,如果它是一条线,您可以在 SVGGraphics2D 中绘制该线。例如:

g2D.drawLine((int) line.getStartX(), (int) line.getStartY(), (int) line.getEndX(), (int) line.getEndY());

请注意,您还需要注意应用于节点的变换以及节点的填充或绘制。

然后你迭代节点子节点并递归地做同样的事情。

最后,您应该能够将文档保存在 SVG 中,因为 Batik 允许本地执行此操作。

于 2016-04-10T15:44:55.860 回答