Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX WebView html loader not loading images

Tags:

java

html

javafx

Well, I have an html file with a tag that points to an image inside the folder /img/. Through a JavaFX window application (not in the same path of the html file) I load the html file but the image does not load. Here's how I load the html file:

@FXML
WebView webView; // I get the webView through @FXML annotation

...
webView.getEngine().loadContent("path/to/file.html");

HTML file structure:

path/to/file.html
path/to/img/image.png

Here's HTML content:

<h1 style="color:red; font-style: italic">
    This is opencraft's presentation :)
</h1>
<img src="img/image.png">
<p>
    This is a simple description of how the game works, lol.
</p>

THE IMAGE GET LOADED IF I LOAD IT WITH THE BROWSER

Anyone could help me?

like image 403
loryruta Avatar asked Dec 30 '16 17:12

loryruta


2 Answers

Basically, the issue is that you need a complete URL, including the scheme etc, for relative links within the html to work. A URL that is relative to the current class or the working directory will not work.

Assuming the html file and the associated image are bundled with the application (i.e. when you build a jar file for the application, the html file and image will be part of the jar file), then you can retrieve a URL for the html file with

getClass().getClassLoader().getResource("path/to/file.html");

where the path is relative to the classpath. You can then use toExternalForm() to convert to a String in the appropriate format. This is appropriate for html help pages, etc.

Here is an example:

HTMLTest.java:

package htmltest;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class HTMLTest extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        WebView webView = new WebView();
        webView.getEngine().load(getClass().getClassLoader().getResource("htmltest/html/test.html").toExternalForm());
        Scene scene = new Scene(webView, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }


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

test.html:

<html>
    <head><title>Test</title></head>
    <body>
        <h1>Test page</h1>
        <img src="img/testImage.png"/>
    </body>
</html>

testImage.png:

enter image description here

Project layout:

htmltest
  - HTMLTest.class
  - html
    - test.html
    - img
      - testImage.png

Screenshot:

enter image description here

On the other hand, if you are genuinely loading the HTML file from the filesystem, you can create a File object for the HTML file, and then convert that to a URI. This would be appropriate, for example, if you were writing an HTML editor in which the user edited the HTML file and saved it to the file system, and you wanted to display the result in a web view; or alternatively if you prompted the user to load an HTML file with a FileChooser.

The code for this would look like:

File htmlFile = new File(...); // or get from filechooser...
webEngine.load(htmlFile.toURI().toString());
like image 149
James_D Avatar answered Nov 11 '22 09:11

James_D


I ran into the same problem and solved it by modifying the src reference in the image at runtime. This code will work when run inside of your IDE and when the application is run in a JAR file. Tested using 1.8.0_121 on Ubuntu and Windows 10.

   Platform.runLater( () -> {
        WebView webView = new WebView();
        WebEngine webEngine = webView.getEngine();

        webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
                if (newState == Worker.State.SUCCEEDED) {
                     NodeList nodeList = doc.getElementsByTagName("img");
                    for (int i = 0; i < nodeList.getLength(); i++) {
                        HTMLImageElement n = (HTMLImageElement)nodeList.item(i);
                        String path = n.getSrc();
                        if( path.startsWith("file://")) {
                            path = path.substring(7,path.length());
                        } else if( path.startsWith("jar:")) {
                            path = path.substring(4,path.length());
                        }

                        URL m = YOURCLASS.class.getResource(path);
                        if( m != null ) {
                            n.setSrc(m.toExternalForm());
                        }
                    }
                }
            }
        });
        webEngine.load( url );
    }

Inside your HTML you should specify the image using the full resource path. You can use a relative path if you're careful with the selection of YOURCLASS.

like image 35
lessthanoptimal Avatar answered Nov 11 '22 10:11

lessthanoptimal