我是 JavaFX 2.2 的新手,到目前为止,我找不到在我的 JavaFX 2.2 应用程序中显示 SVG 图像的方法。我看了看 Batik,但它并没有对我有用,因为它转换BufferedImages
为javafx.ImageView
.
有没有办法在 JavaFX 应用程序中显示 SVG 图像?或者您至少可以从 JavaFX 导出 SVG 图像吗?该功能Node.snapshot()
对那里有任何帮助吗?
有没有办法在 JavaFX 应用程序中显示 SVG 图像?
以下是一些选项:
或者您至少可以从 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 等效项(例如渐变、效果和转换)。
我使用上面的转码器类在 github 上创建了一个小项目,为 JavaFX(尽管是 JavaFX 8)添加了 SVG 支持:javafxsvg
打电话后
SvgImageLoaderFactory.install();
您可以在 Java 代码或 CSS 中的任何位置使用 SVG 图像,就像任何其他受支持的图像类型一样。
由于我没有找到将 Batik 与 JavaFX 结合使用的完整示例,因此我在下面提供了一个完整的解决方案。
请注意,TranscoderException
为简洁起见,我删除了异常处理(例如对于 )。
您可以在此处访问完整代码:https ://gist.github.com/ComFreek/b0684ac324c815232556
为了将带有 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;
}
}
使用转码器生成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);
我不想使用需要蜡染的库,所以我在这里开发了一个没有依赖关系的小库:https ://github.com/hervegirod/fxsvgimage
有一些方法可以生成 JavaFX 节点树,还有一些方法可以生成图像。
主类也命名为SVGLoader
,但这个库是自包含的。当然,它可能不支持 Batik 的完整扩展。
使用 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/