JavaFX 2.2中的SVG图像

33

我对JavaFX 2.2还不熟悉,目前我找不到在JavaFX 2.2应用程序中显示SVG图像的方法。我查看了Batik,但它没能为我完成任务,因为它将SVG转换为BufferedImages而不是javafx.ImageView

有没有办法在JavaFX应用程序中显示SVG图像?或者你至少能从JavaFX导出SVG图像吗?Node.snapshot()函数是否有帮助?

5个回答

55
有没有办法在JavaFX应用程序中显示SVG图像?
以下是一些选项:
  1. 创建一个 WebView 并将 svg 图像加载到 WebView 的 WebEngine 中。
  2. e(fx)clipse 项目包括一个 svg to fxml 转换器(链接已失效 :()。
  3. 这个 NetBeans 插件 也可以将 svg 转换为 fxml(链接已失效 :()。
  4. 您可以使用基于 awt 的库,例如 Batiksvgsalamander ,并将生成的 BufferedImage 转换为 JavaFX 图像。
  5. JavaFX 2.2 本地支持一些最小的 SVGPath 字符串(不是完整的 SVG 规范)。
  6. 您可以编写一个转换器,使用 JavaFX Canvas GraphicsContext 命令呈现 svg。
  7. FranzXaver 提供了一个 SVGLoader,其用法在回答中演示:在 JavaFX 中在按钮上加载 SVG 文件
  8. https://github.com/hervegirod/fxsvgimage
    • 该库允许将 SVG 文件转换为 JavaFX Node 树或图像。
    • 请注意,与其他现有库相反,此库没有外部依赖项(包括 Batik)

或者你能否至少从JavaFX中导出SVG图像?

这个功能听起来像是JavaFX场景图到svg转换器。虽然在理论上是可能的,但我不知道是否已经有人创建了这样的工具。

函数Node.snapshot()能帮助吗?

Node.snapshot()对于从JavaFX场景图导出svg图像没有帮助,因为svg是一种基于矢量的格式,而节点快照是一种位图格式。

我看了一下Batik,但它不能将图像转换为javafx.ImageView,只能转换为BufferedImages。

您可以使用SwingFXUtils轻松地在awt BufferedImages和javafx images之间进行转换。

就性能而言,你会推荐哪种方式?

对于复杂的SVG图形,与其从FXML渲染,您可能会获得更好的性能,将其渲染为位图图像或画布图形上下文。这是因为您的场景图将变得简单得多,节点要少得多,这意味着JavaFX运行时需要做的工作要少得多。对于简单的SVG(< 1000个生成的节点),这可能不太重要。
部分是的。完整的SVG规范涵盖了比基本形状更多的内容。此外,渐变、效果、动画等也可以通过SVG执行。因此,如果源SVG图像包括这些附加项,则它们也需要转换为FXML(尽可能地转换,但有些SVG方面,如脚本编写,很难转换为FXML)。
我的猜测是,SVG规范的大小和复杂性是目前JavaFX核心API中没有直接支持完整SVG图像系统的原因之一,而只提供了类似SVGPath的有限功能。在JavaFX核心API中实现SVG本地化将会付出高昂的成本,相对于其他理想的项目来说回报很少。

如果是这样,那么#2(和#3)和#5不是一样的吗?

不是。在#2和#3中引用的NetBeans和Eclipse工具比#5中提到的SVGPath功能更加功能强大,因为这些工具将SVG规范的其他方面转换为FXML等效项(例如渐变,效果和变换)。

1
感谢您详细的回答!就性能而言,您会推荐哪种方式?将它们全部转换为FXML吗? - user1582432
谢谢!我想给你的答案点赞,但是我没有足够的声望来做到这一点。抱歉! - user1582432
@jewelsea 将SVG转换为FXML是关于创建javafx.scene.shape.SVGPath实例吗?如果是这样,那么#2(和#3)和#5不是完全相同吗?或者你在#5中提到了另一个SVGPath?(编辑:显然它与我看到的链接相同。所以我更想问#2和#3是否与javafx.scene.shape.SVGPath无关。)我正在查看此示例:https://raw.githubusercontent.com/usander/e-fx-clipse/master/at.bestsolution.efxclipse.formats.svg/samples/application-exit.fxml - konsolebox
你应该添加这个库 https://github.com/hervegirod/fxsvgimage,因为它不使用Batik。 - trilogy
@trilogy 谢谢,我已经将hervegirod fxsvgimage的链接添加到选项列表中。 - jewelsea

28

我使用上述转码器类在Github上创建了一个小项目,该项目为JavaFX(JavaFX 8)添加了SVG支持:javafxsvg

在调用后,

SvgImageLoaderFactory.install();

您可以像使用任何其他支持的图像类型一样,在Java代码或CSS中的任何地方使用SVG图像。


2
这个解决方案的问题在于它依赖于 Batik,而 Batik 已经损坏了,并且没有任何迹象表明它会在不久的将来得到修复。 - Dave

11

JavaFX + Batik + 自定义转码器

由于我没有找到一个完整的示例来展示如何将Batik与JavaFX配合使用,因此在下面提供了一个完整的解决方案。

请注意,为了简洁起见,我删除了异常处理(例如TranscoderException)。
您可以在此处访问完整代码https://gist.github.com/ComFreek/b0684ac324c815232556

  1. 要使用Batik将SVG文件转换为BufferedImage,您需要实现一个自定义的转码器:

/**
 * Many thanks to bb-generation for sharing this code!
 * @author bb-generation
 * @link http://bbgen.net/blog/2011/06/java-svg-to-bufferedimage/
 * @link In case the link above is still down: https://web.archive.org/web/20131215231214/http://bbgen.net/blog/2011/06/java-svg-to-bufferedimage/
 */

public class BufferedImageTranscoder extends ImageTranscoder {

    private BufferedImage img = null;

    @Override
    public BufferedImage createImage(int width, int height) {
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        return bi;
    }

    @Override
    public void writeImage(BufferedImage img, TranscoderOutput to) throws TranscoderException {
        this.img = img;
    }

    public BufferedImage getBufferedImage() {
        return img;
    }
}
使用转码器生成一个BufferedImage对象:
BufferedImageTranscoder trans = new BufferedImageTranscoder();

// file may be an InputStream.
// Consult Batik's documentation for more possibilities!
TranscoderInput transIn = new TranscoderInput(file);

trans.transcode(transIn, null);
  • BufferedImage 对象转换为 Image 对象(来自 JavaFX):

  • // Use WritableImage if you want to further modify the image (by using a PixelWriter)
    Image img = SwingFXUtils.toFXImage(trans.getBufferedImage(), null);
    
    最后,将之前接收到的对象分配给你的ImageView
    imgView.setImage(img);
    

    2
    Batik在Java9+上已经破裂了几年,维护者似乎对修复它不太感兴趣,因此如果您需要在过去5年中发布的JRE上运行,追求这种方法将是浪费时间。有关详细信息,请参见https://issues.apache.org/jira/browse/BATIK-1260。再加上厨房水槽非可选依赖项,这些依赖项遮盖了常见的api jar - 例如jython - 我不建议在生产代码中使用Batik。 - Dave
    @Dave https://github.com/hervegirod/fxsvgimage 不使用 Batik。 - trilogy
    @三合一 - 这个答案并不涉及fxsvgimage。 - Dave
    我知道,我只是想让你知道。 - trilogy

    2

    我不想使用需要batik的库,所以我开发了一个没有依赖关系的小型库,链接在这里:https://github.com/hervegirod/fxsvgimage

    它有生成JavaFX节点树的方法和生成图像的方法。

    主要类也被命名为SVGLoader,但这个库是自包含的。当然,它可能不支持完整的Batik功能。


    1
    用了这个,谢谢。如何设置SVG图像的宽度,例如“setPrefWidth(50)”?我不想转换为java.Image,因为当您在显示器上缩放DPI时,图像会变成光栅化。我能够通过使用正确大小的SVG获取宽度,但如果我没有呢? - trilogy
    1
    你可以使用LoaderParameter类并设置比例或宽度。例如:LoaderParameters params = new LoaderParameters(); params.width = 50; SVGImage image = SVGLoader.load(<我的svg>, params); - Hervé Girod
    谢谢,我会试一下。你什么时候会在Maven上? - trilogy
    这是一个非常受欢迎的功能,我知道。目前,可以通过jitpack实现,我将尝试在下周之前添加适当的Maven支持 :) - Hervé Girod

    -1
    使用WebView。以下是一个加载SVG并支持CSS动画的工作示例:
    • 控制器类 SplashController.java:

      public class SplashController implements Initializable {
            @FXML
            private StackPane rootPane;
            @FXML private WebView webView; 
            private WebEngine webEngine; 
                public void initialize(URL url, ResourceBundle rb) {
                 webEngine = webView.getEngine();
                  URL url1 = getClass().getResource("/android_switch_string.svg");
                  webEngine.load(url1.toExternalForm());
                }
        }
      
    • 资源文件 splash_svg.fxml:

      < StackPane fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="360.0" prefWidth="508.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="diagnosticsWin.SplashController">
              <children>
                <WebView fx:id="webView" prefHeight="200.0" prefWidth="200.0" />
              </children>
            </StackPane>
      

    完整的代码描述 https://www.ap-impulse.com/splash-screen-and-javafx-statya-106/

    项目 https://github.com/nik137/Diagnostics


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接