【问题标题】:How can I export a JavaFX node to an SVG image?如何将 JavaFX 节点导出为 SVG 图像?
【发布时间】:2012-09-17 04:25:20
【问题描述】:

换句话说,我正在尝试用 JavaFX 做一些事情,比如 Batik allows you to do with Swing.

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

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

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

【问题讨论】:

  • 绝对有可能。我不知道任何现有的实现。
  • 但是你会从哪里开始呢?我已经做了很多 Swing(通过实现自定义 Graphics2D 对象可以轻松解决这个问题),但我真的找不到等效的方法来获取 JavaFX 中的底层渲染调用。
  • 取决于您的范围,您想为 JavaFX Canvas GraphicsContextJavaFX FXML file 或任意 SceneGraph Node 执行此操作吗?
  • 您需要绝对保真导出的 SVG 中的 JavaFX 渲染,还是只需要接近 JavaFX 场景的东西?是否要考虑 JavaFX css 应用程序?
  • 我正在尝试做任意的 SceneGraph 节点,导出的输出不需要完美的保真度,虽然它应该很接近,而且我们没有用 css 做任何花哨的事情,所以它可能是忽略...

标签: java svg javafx vector-graphics


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

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

    考虑未来的版本。

    并且标记为版本 9。

    【讨论】:

      【解决方案3】:

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

      https://github.com/stefaneidelloth/JavaFxNodeToSvg

      ...在一定的挫败感之后停止了它。

      请随时改进、添加功能和修复错误。

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

      简单节点示例(有效):

      图表示例(不起作用):

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

      https://github.com/stefaneidelloth/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 图表的转换能够成功,我会非常高兴,这样我就可以在我的一个项目中使用 JavaFx 绘图和 SVG 导出。

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

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

      【讨论】:

        【解决方案4】:

        这个想法是,如果您能够将 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 允许在本机进行此操作。

        【讨论】:

          【解决方案5】:

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

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

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

          如何执行转换:

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

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

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

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

          您还必须注意节点的 CSS 属性。

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

          【讨论】:

          • 请在您之前的答案中使用“编辑”链接(或保留此答案并使用“删除”链接删除旧答案),而不是添加新答案。
          • FWIW 这是一个很好的编辑。但你应该听从安德拉斯的建议。
          猜你喜欢
          • 1970-01-01
          • 2023-04-05
          • 2012-09-02
          • 1970-01-01
          • 2019-05-27
          • 2018-09-23
          • 2013-07-01
          • 2015-09-21
          相关资源
          最近更新 更多