31

我是 JavaFX 2.2 的新手,到目前为止,我找不到在我的 JavaFX 2.2 应用程序中显示 SVG 图像的方法。我看了看 Batik,但它并没有对我有用,因为它转换BufferedImagesjavafx.ImageView.

有没有办法在 JavaFX 应用程序中显示 SVG 图像?或者您至少可以从 JavaFX 导出 SVG 图像吗?该功能Node.snapshot()对那里有任何帮助吗?

4

5 回答 5

52

有没有办法在 JavaFX 应用程序中显示 SVG 图像?

以下是一些选项:

  1. 创建一个WebView并将svg 图像加载到 WebView 的 WebEngine 中。
  2. e(fx)clipse项目包括一个svg 到 fxml 的转换器(链接现已失效:()。
  3. NetBeans 插件还将 svg 转换为 fxml(链接现已失效:()。
  4. 您可以使用基于 awt 的库,例如Batiksvgsalamander,并将生成的 BufferedImage 转换为 JavaFX 图像。
  5. JavaFX 2.2 原生支持一些最小的SVGPath字符串(不是完整的 SVG 规范)。
  6. 您可以编写一个转换器,使用 JavaFX Canvas GraphicsContext命令呈现 svg 。
  7. FranzXaver提供了一个 SVGLoader,其用法在答案中得到了演示:Load SVG file in a Button on JavaFX

或者您至少可以从 javafx 导出 SVG 图像吗?

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

函数 Node.snapshot() 有什么帮助吗?

Node.snapshot()不会帮助从 JavaFX 场景图中导出 svg 图像,因为 svg 是基于矢量的格式,而节点快照是位映射格式。

我看了一下 Batik,但它并没有对我有用,因为它转换为 BufferedImages 而不是 javafx.ImageView。

您可以使用SwingFXUtils在 awt BufferedImages 和 javafx 图像之间轻松转换。

在性能方面 - 您会推荐哪种方式?

对于复杂的 svg,而不是从 fxml 渲染,您可能会获得更好的性能渲染到位图图像或画布图形上下文。这是因为您的场景图最终会简单得多,节点少得多 - 这意味着 javafx 运行时要做的工作要少得多。对于简单的 svgs(生成 < 1000 个节点),它可能不会太重要。

将 SVG 转换为 FXML 关于创建 javafx.scene.shape.SVGPath 的实例?

部分。完整的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 等效项(例如渐变、效果和转换)。

于 2012-09-15T19:36:35.967 回答
28

我使用上面的转码器类在 github 上创建了一个小项目,为 JavaFX(尽管是 JavaFX 8)添加了 SVG 支持:javafxsvg

打电话后

SvgImageLoaderFactory.install();

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

于 2015-04-14T13:47:41.050 回答
12

JavaFX + Batik + 自定义转码器

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

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

  1. 为了将带有 Batik 的 SVG 文件转换为 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;
        }
    }
    
  2. 使用转码器生成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);
    
  3. BufferedImage对象转换为Image对象(来自 JavaFX):

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

    imgView.setImage(img);
    
于 2014-05-27T16:17:50.867 回答
1

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

有一些方法可以生成 JavaFX 节点树,还有一些方法可以生成图像。

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

于 2021-07-03T10:51:22.990 回答
-1

使用 Web 视图。下面是加载 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

于 2021-12-08T05:48:51.280 回答