1 2 Previous Next 16 Replies Latest reply: Feb 7, 2012 2:12 AM by 915777 RSS

    Setting html content with setContent() does never show images

    909505
      I've an application set sets dynamically generated html-content in a webview node by using the webengine.setContent() method. This generated html content uses image-tags.
      Here's the problem: the image is not displayed. I tried all variations (absolute url like "http://localhost/c:/test.png" or "file://c:/test.png", relative urls like "test.png" with png in jar-file).

      Anyone out there who has a workaround for me? I appreciate any comment.
        • 1. Re: Setting html content with setContent() does never show images
          jsmith
          This DatePicker I wrote based on JQueryUI, uses html content loaded via webView.getEngine().loadContent() and it displays images (hosted on an external http server) fine.
          http://jewelsea.wordpress.com/2011/12/05/jqueryui-based-datepicker-for-javafx/ (screenshot)
          https://gist.github.com/1422815 (source)
          • 2. Re: Setting html content with setContent() does never show images
            909505
            Hi JSmith,
            Thanks for the reply. Your sourcecode is well structured and easy to understand - nice.
            In your datepicker in method getInlineHtml() you use absolute http-urls to load css and js files. But I have a standalone application and no webserver running. What I need is to load such files (images in my case) from my local drive (for examle from c:/test.png). Note that I tried loading images from a remote webserver. That works perfectly.

            Sample html which I generate dynamically and want to display:
            <html>
            <body> 
            one non-working apple <img src="apple.png"> 
            and two non-working peaches <img src="http://localhost/c:/peaches.png"> 
            and a working remote image url <img src="http://docs.oracle.com/javafx/javafx/images/javafx-documentation.png">
            </body>
            </html>
            Sample usage in javafx:
            WebView webView = new WebView();
            WebEngine engine = webView.getEngine();
            engine.loadContent(... the html from above ...);
            Edited by: user5922802 on 07.01.2012 09:15

            Edited by: user5922802 on 07.01.2012 09:16
            • 3. Re: Setting html content with setContent() does never show images
              aidreamer
              For security reasons, a web browser won't let a web page access files on your file system unless the web page itself is on the file system. I cannot use JavaFX myself, but I would imagine that it does the same thing. Perhaps you could write the html file directly on to your system and feed JavaFX the url to it.
              • 4. Re: Setting html content with setContent() does never show images
                jsmith
                one non-working apple <img src="apple.png">
                You loaded the page content with loadcontent, then inside the page content provided a relative url. This is likely an error.

                The question is, what is this url relative to?
                The answer is either likely undefined as no protocol was used to load the page content and so it can't be determined how to load the relative url resource.
                and two non-working peaches <img src="http://localhost/c:/peaches.png">
                You attempted to load content using the http protocol server on the localhost, but you have no such server on the host, so this cannot work.
                and a working remote image url <img src="http://docs.oracle.com/javafx/javafx/images/javafx-documentation.png">
                This works because you fully specified how to load the content by providing the protocol and valid resource reference.

                --------------

                OK, so the question remains how do you images from the local drive?

                There are three options for this in the following code.
                package org.jewelsea.examples.webviewlocal;
                
                import javafx.application.Application;
                import javafx.beans.value.*;
                import javafx.scene.Scene;
                import javafx.scene.layout.FlowPane;
                import javafx.scene.web.WebView;
                import javafx.stage.Stage;
                
                /** Example of a webview loading resources from the file system. */
                public class WebViewLocal extends Application {
                  public static void main(String[] args) throws Exception {
                //    URL.setURLStreamHandlerFactory(new HandlerFactory());
                    launch(args);
                  }
                
                  public void start(final Stage stage) throws Exception {
                    final FlowPane layout = new FlowPane();
                
                    WebView webView = new WebView();
                    webView.getEngine().load("file:///C:\\dev\\gettingstarted\\timeforgotten.html");
                //    webView.getEngine().load("jar:file:///C:\\dev\\javafx\\JavaFXidea\\out\\artifacts\\JavaFXidea_jar\\JavaFXidea.jar!/org/jewelsea/examples/webviewlocal/timeforgotten.html");
                //    webView.getEngine().load("resource:///org/jewelsea/examples/webviewlocal/timeforgotten.html");
                    webView.getEngine().getLoadWorker().exceptionProperty().addListener(new ChangeListener<Throwable>() {
                      @Override public void changed(ObservableValue<? extends Throwable> observableValue, Throwable oldThrowable, Throwable newThrowable) {
                        System.out.println("Load exception: " + newThrowable);
                      }
                    });
                
                    // layout the scene.
                    layout.getChildren().addAll(webView);
                    Scene scene = new Scene(layout, 1000, 600);
                    webView.prefWidthProperty().bind(scene.widthProperty());
                    webView.prefHeightProperty().bind(scene.heightProperty());
                
                    stage.setScene(scene);
                    stage.show();
                  }
                }
                which loads the following html file:
                <html>
                <head>
                  <style type="text/css">p { color: sienna; font-size: 20px; text-align: center; }</style>
                </head>
                <body bgcolor="cornsilk">
                <p><em>
                    <br/>
                    On either side the river lie,<br/>
                    Long fields of barley and of rye,<br/>
                    And through the fields a road runs by,<br/>
                    To many towered Camelot.
                </em></p>
                <p><img src="camelot.jpg"/></p>
                </body>
                </html>
                If you want to test this example the camelot.jpg image is downloadable from http://www.timelessmyths.com/arthurian/gallery/camelot.jpg.

                Option 1: The file:// protocol for lookup from the filesystem.
                This is the most straight-forward as it is just based on standard html layout in the filesystem - just place your html and it's relative referenced images somewhere in your filesystem in locations relative to each other - if your browser loads it properly, then your webengine will to if you give it the right file:// path.
                In the case of file:///C:\\dev\\gettingstarted\\timeforgotten.html, timeforgotten.html is placed in c:\dev\gettingstarted and camelot.jpg image is placed in the same directory.

                Option 2: The jar:file:// protocol for lookup from a jar hosted on the filesystem.
                This makes use of the http://docs.oracle.com/javase/7/docs/api/java/net/JarURLConnection.html to find your resources.
                If your application resources are packaged in a jar file (could be the same jar file as your main application class) then you can reference the jar file through the file protocol, then pick out the resources packaged in the jar file via their relative paths.

                Option 3: The resource:// protocol for lookup based on the classpath.
                This type of resource lookup is the one most Java programmers are familiar with - a classloader is used to load a resource. The pattern is widely used in web application frameworks on the server. But usually the means to do this is via a classloader.getResource() call, not via a URL.
                Java does not, by default, have a URL protocol handler for looking up resources on the classpath, so if you want to do this, it is necessary to create your own protocol and install it.
                The installation function is the commented out line: // URL.setURLStreamHandlerFactory(new HandlerFactory());
                It is a system wide call for the VM and should be called (just once) before any URL Connections are established.
                To get this to work I used a resource handler from http://www.arakhne.org/arakhneVmutils/index.html which included the following classes:
                  java.org.arakhne.vmutil.resource.Handler
                  java.org.arakhne.vmutil.resource.HandlerFactory
                  java.org.arakhne.vmutil.resource.URLConnection
                  java.org.arakhne.vmutil.ClassLoaderFinder
                  java.org.arakhne.vmutil.Resources
                  java.org.arakhne.vmutil.ResourceNotFoundException
                  java.org.arakhne.vmutil.URISchemeType
                  java.org.arakhne.vmutil.URLHandlerUtil
                Details on how all this works are in http://java.sun.com/developer/onlineTraining/protocolhandlers/ which defines "A New Era for Java Protocol Handlers" by defining a URL handler extension mechanism which is hardly ever used.

                As a final note to my way overly long forum post, when the WebEngine doesn't process the urls sometimes you can get info on what went wrong via the monitoring the loadWorker's exception property, but sometimes I was able to get more complete stack traces by trying to open a connection on a URL to see if I had got the URL correct - for example:
                    URL url = new URL("jar:file:///C:\\dev\\javafx\\JavaFXidea\\out\\artifacts\\JavaFXidea_jar!/org/jewelsea/examples/webviewlocal/timeforgotten.html");
                    url.openConnection();
                Anyway, just using the file:// protocol in webEngine.load() will probably accomplish what you need.
                Note that if it is a webstart or browser embedded app, then you'll need to sign it if you want to access the local file system.
                • 5. Re: Setting html content with setContent() does never show images
                  909505
                  Hi aidreamer,

                  You are right - that would solve my problem. But my application shows a lot of (many thousands) html snippets in a table. And those snippets are generated dynamically in my application and contain img-tags to images that are on my filesystem. It would be really a lot of overhead to write all those files to the filesystem - just to load them right afterwards.
                  In swing I used an approach to intercept the resolution of the IMG tag by using an own implementation of the HtmlEditorKit. That was great because it allowed me to load my IMG-images from anywhere and even apply some own caching-mechanisms. In JavaFx I do not have such a possibility (or at least I did not find it yet).

                  Thanks for your comment,
                  Uli
                  • 6. Re: Setting html content with setContent() does never show images
                    909505
                    Hi jsmith,

                    Your example works because the html file is in the local directory and you load it by URL. But I need a solution to set the html-content directly. I generate many html-snippets which I display in a table. And the snippets contain text and IMG-Tags which reference locally stored images.
                    LoadWorker gave me no hint. It probably does not throw an exception because I use loadContent().
                    I have to check the protocolhandler approach. Maybe there's a way to intercept the resolution of IMG-Tags when the html-snippet is displayed.

                    Thanks for your long explanation.
                    Uli
                    • 7. Re: Setting html content with setContent() does never show images
                      Richard Bair-Oracle
                      I believe there is a way in Java to intercept all URL requests by installing your own URL handler. I don't remember the API but you should be able to find it in the java.net package I think. You could then send your own unique URL (like myapp://someURL) and handle it as you please.

                      Richard
                      • 8. Re: Setting html content with setContent() does never show images
                        893762
                        The fact that the content loaded with WebEngine.loadContent() cannot reference local resources is in fact a bug - http://javafx-jira.kenai.com/browse/RT-17930 , which is going to be fixed as part of another bug - http://javafx-jira.kenai.com/browse/RT-17330 - in JavaFX 2.1. The fix should already be included in the latest 2.1 developer preview version.

                        Edited by: Vasiliy Baranov on Jan 13, 2012 5:01 AM
                        • 9. Re: Setting html content with setContent() does never show images
                          jsmith
                          I believe there is a way in Java to intercept all URL requests by installing your own URL handler. I don't remember the API but you should be able to find it in the java.net package I think. You could then send your own unique URL (like myapp://someURL) and handle it as you please.
                          Yes, a sample solution is in my previous post - I should avoid overly long posts I guess.
                          The installation of your own URL handler is accomplished by:
                          URL.setURLStreamHandlerFactory(new HandlerFactory())
                          • 10. Re: Setting html content with setContent() does never show images
                            jsmith
                            The fact that the content loaded with WebEngine.loadContent() cannot reference local resources is in fact a bug ... which is going to be fixed
                            Hi Vasily,
                            In the fix for bug http://javafx-jira.kenai.com/browse/RT-17330, the sample reference is <script src="file:///C:/projects/test.js"></script>
                            I assume that, if you load the test.html file using loadContent("test.html"), that a relative reference to the test.js resource (e.g. <script src="test.js">) will not work (i.e. test.js will not be loaded as a resource from the classpath) even with the 17330 fix in place (this is the behaviour I encountered with 2.1b7 code).
                            • 11. Re: Setting html content with setContent() does never show images
                              893762
                              Well, if you already have the test.html file, you are likely to be loading it via WebEngine.load("file:///<path-to>/test.html"), in which case relative references appearing in test.html are supposed to work.

                              However, in the contents loaded via WebEngine.loadContents("<html>...</html>"), relative references are not going to work until something like http://javafx-jira.kenai.com/browse/RT-12170 is implemented.

                              Edited by: Vasiliy Baranov on Jan 16, 2012 1:33 AM
                              • 12. Re: Setting html content with setContent() does never show images
                                jsmith
                                Thanks for the reply Vasily, that's very clear now.
                                • 13. Re: Setting html content with setContent() does never show images
                                  jsmith
                                  I found some simple ways to get resources resolved from loadContent in Sergey's answer to this stackoverflow question http://stackoverflow.com/questions/8923801/how-to-reach-css-and-image-files-from-the-html-page-loaded-by-javafx-scene-web-w/8931543#8931543
                                  view.getEngine().loadContent("<img src='" + getClass().getResource("1.jpg") + "' />");
                                  Also peterz pointed out here Re: Image in HTML document mising, when application is started out of the jar that you can load html from the classpath and have all of the relative links resolved from the classpath as well using:
                                  webEngine.load(getClass().getResource("/resources/game.html").toExternalForm());
                                  Both of these techniques are much more straightforward than creating you own url handler as I suggested earlier.
                                  • 14. Re: Setting html content with setContent() does never show images
                                    912488
                                    Hi Jsmith,

                                    I tried the solution
                                    view.getEngine().loadContent("<img src='" + getClass().getResource("1.jpg") + "' />");
                                    It doesn't work for me. Can you please help me to check what is wrong with my code.
                                    I have an output.html which contains a img tag link to logo.png in the same directory.
                                    Here is my code
                                            final WebView webView = WebViewBuilder.create().prefHeight(450).prefWidth(1000).build();
                                            URL url = getClass().getResource("/output.html");
                                            String externalForm = url.toExternalForm();
                                            webView.getEngine().load(externalForm);
                                    The webView.getEngine().load() method works well and the image is displayed in the HTML page.

                                    But when I use the loadContent() to load the image. It doesn't show up
                                            WebView webView = WebViewBuilder.create().prefHeight(450).prefWidth(1000).build();
                                            String img = "<img src='" + getClass().getResource("/logo.png") + "' />";
                                             webView.getEngine().loadContent(img);
                                    1 2 Previous Next