Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request for Direct SVG to JavaFX Image Conversion to Support Packaging with Gluon/GraalVM #54

Open
leewyatt opened this issue Oct 25, 2023 · 10 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@leewyatt
Copy link

Hello,

I am reaching out to suggest a feature for the JSVG library that I believe would be beneficial for JavaFX applications, particularly those that aim to achieve native packaging.

As you may know, in order to package a JavaFX application natively with tools such as Gluon or GraalVM, it is necessary to avoid using classes from the AWT package, as these are not supported. In the context of this project, this means avoiding the use of java.awt.image.BufferedImage.

Currently, when using JSVG in a JavaFX application, we have to convert BufferedImage to JavaFX's Image in order to display SVG icons. However, this approach prevents us from utilizing tools like Gluon/GraalVM for native packaging.

Given this, I would like to request the possibility of directly converting SVG files to JavaFX's Image. This should not be overly complex to implement, and it would greatly facilitate the use of SVG icons in JavaFX applications, without the aforementioned complications regarding native packaging.

You might consider adding a JavaFX module or creating a new branch specifically adapted for JavaFX.

Thank you for your wonderful work on JSVG; it is truly an excellent library, and your contributions are greatly appreciated.

Best regards,

@weisJ weisJ added enhancement New feature or request help wanted Extra attention is needed labels Oct 25, 2023
@weisJ
Copy link
Owner

weisJ commented Oct 25, 2023

I can see that this would be a desirable feature for JavaFX applications. Though the implementation would be a huge undertaking. The usage of BufferedImages can't easily be replaced as they are tightly integrated into the rendering process especially for filters and masks. Moreover everything is rendered to a java.awt.Graphics2D object. A rewrite would need to happen through the entire rendering stack to allow for javafx.scene.canvas.GraphicsContext (I guess this is this the JavaFX equivalent. I don't have much experience with JavaFX).

To be honest I don't think that I have the resources at the moment to make it happen any time soon. Though I would be willing to guide through needed changes for a PR.

@leewyatt
Copy link
Author

Thank you for your response. It seems that due to my limited knowledge on rendering, I've oversimplified the issue. I hope that some knowledgeable expert in this field would be willing to help resolve this problem.

@weisJ
Copy link
Owner

weisJ commented Feb 15, 2024

Are all classes from java.awt unsupported or is it only BufferedImage specifically? With the latest changes regarding support for shape computation I have moved forward with abstracting away the underlying render target. It would allow to make an implementation for JavaFX more feasible. One would have to implement com.github.weisj.jsvg.renderer.Output
for it. Though <mask>, <filter> and soft clipping for <clipPath> still rely on BufferedImage, however SVGs without them could be rendered this way.

@leewyatt
Copy link
Author

Thank you very much for your detailed response . It's greatly appreciated and speaks volumes of your dedication to the JSVG library.

Our objective is to avoid all java.awt classes to ensure the widest compatibility and performance optimization for JavaFX applications. This includes BufferedImage among others.

@weisJ
Copy link
Owner

weisJ commented Feb 16, 2024

Let me be a bit more explicit with may question:

Do you know if there is a certain subset of java.awt which causes incompatibility with native packaging? For example I don’t quite see why the Path related apis would cause problems. Are they supported?

@leewyatt
Copy link
Author

Thank you for your insightful questions. Allow me to address them as follows:

  1. Regarding the Path API: In JavaFX, there is a similar class, javafx.scene.shape.Path, which allows for the drawing of various shapes. This class might serve as a direct alternative for drawing functionalities in a JavaFX environment. You can find more details about it in the JavaFX documentation: JavaFX Path Documentation.

  2. On the relationship between JavaFX native packaging and AWT: I came across a useful reference that might shed some light on this issue. A reply from José Pereda on Stack Overflow discusses the compatibility issues between Swing/JavaFX and native packaging with GraalVM, specifically regarding the 'No AWT in java.library.path' error. This discussion seems highly relevant to our conversation: Swing and JavaFX native image with GraalVM.

  3. Assistance and Testing: I am more than willing to assist in testing or provide any help within my capabilities. If there are specific scenarios or configurations you'd like me to explore, please let me know.

@leewyatt
Copy link
Author

JavaFX indeed includes an SVGPath class, which is primarily geared towards supporting path data similar to the "path" element in SVG files. However, when it comes to SVG icons that incorporate other shapes like circles, lines, rectangles, ellipses, polygons, and text, manual drawing and coordinate calculation are required. Fortunately, JavaFX provides comprehensive APIs for drawing these shapes, which means that transforming these SVG elements into JavaFX equivalents is feasible but demands familiarity with SVG syntax and semantics.

For those well-versed in SVG, adapting SVG icons to JavaFX manually can be a detailed but rewarding process, as JavaFX's drawing capabilities are extensive. The process involves interpreting the SVG elements and attributes and then using JavaFX's graphical primitives to render them accordingly.

Regarding performance, utilizing the Canvas API in JavaFX might offer superior performance for dynamic or complex drawings because it allows for direct rendering onto a single graphical surface, which can be more efficient than managing multiple individual shape nodes in a scene graph for highly complex or frequently updated graphics.

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.SVGPath;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class AppMain extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        SVGPath svgPath = new SVGPath();
        // only supports path data in the form of a string
        svgPath.setContent("M 0 0 L 10 10 L 0 20 Z");
        svgPath.setFill(Color.CORAL);

        Circle circle = new Circle(15);
        circle.setFill(Color.AQUA);

        Polygon polygon = new Polygon(0, 0, 5, 5, 0, 10);
        polygon.setFill(Color.DEEPPINK);

        Ellipse ellipse = new Ellipse(15, 35);
        ellipse.setFill(Color.BLUEVIOLET);

        Text text = new Text("Hello");
        text.setFont(Font.font(20));
        text.setFill(Color.DARKORANGE);

        Canvas canvas = new Canvas(100, 100);
        canvas.getGraphicsContext2D().setFill(Color.LIGHTPINK);
        GraphicsContext g2d = canvas.getGraphicsContext2D();
        g2d.fillOval(0, 0, 100, 100);

        HBox group = new HBox(10, svgPath, circle, polygon, ellipse, text, canvas);
        group.setAlignment(Pos.CENTER);
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(new javafx.scene.Scene(group, 520, 230));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

@leewyatt
Copy link
Author

I've attempted to create an RXSVGView, which can parse multiple paths from an SVG icon and fill them with colors extracted directly from the SVG. Essentially, it translates the multiple paths within an SVG icon into individual SVGPath objects and then places them into a Pane container. Fully supporting SVG icons seems to be a daunting task, involving extensive XML parsing, which is why I've limited the implementation to parsing only the paths. RXSVGView Skin source

@weisJ
Copy link
Owner

weisJ commented Feb 19, 2024

Thank you for the additional information. Something that would be very helpful would be a minimal example repository to showcase native packaging.

@leewyatt
Copy link
Author

I found a comprehensive guide on the Gluon website that covers the process of packaging JavaFX applications for various platforms, including Windows, macOS, Linux, Android, and iOS. This guide explains how to use the GluonFX plugin with GraalVM and JavaFX to compile Java client applications and their dependencies into native code for direct execution on these platforms. For detailed steps and more information, you can visit the Gluon documentation page​.

I've been busy troubleshooting a rather tricky bug recently. If, after reviewing the documentation, you feel there's a need for a minimal demo,I will try to write one as soon as possible. However, please note that the minimal demo is not closely related to packaging; the main reference should still be the packaging process outlined in the Gluon documentation. If there's anything else you need from me, please let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants