7 Replies Latest reply: Aug 20, 2012 9:57 PM by jsmith RSS

    load an image in background

    user8244906
      Are there any secrets in loading Images in background? I never succeeded in loding an Image like this: Image image1 = new Image("flower.png", true); If I change this example to an URL "http://..." it will work. But I like to load large Imges from disk. image.isError() will always say "false", image.isBackgroundLoading() is "true" and progress is always 0.0.

      Thank you for your help

      Andy
        • 1. Re: load an image in background
          JohnHendrikx
          I use the code below to load images in the background.

          It is a special type of Property that you can bind to. It has an imageUrl property that you set to the Image you would like to load, and after it is loaded it automatically updates itself so your image is shown. If you change it again later, it will load the new image in the background and update itself again.

          Use it like this:
          AsyncImageProperty imageProperty = new AsyncImageProperty();  // create async image loading property
          
          ImageView view = new ImageView();  // create a View to display images
          view.imageProperty().bind(imageProperty);  // bind to the image property so any changes become visible
          
          imageProperty.imageHandleProperty().set("/my/image/to/load.png");  // set an image to load
          And the class that I use:
          package hs.mediasystem.beans;
          
          import javafx.beans.property.ObjectProperty;
          import javafx.beans.property.SimpleObjectProperty;
          import javafx.beans.value.ChangeListener;
          import javafx.beans.value.ObservableValue;
          import javafx.concurrent.Service;
          import javafx.concurrent.Task;
          import javafx.concurrent.Worker.State;
          import javafx.scene.image.Image;
          
          public class AsyncImageProperty extends SimpleObjectProperty<Image> {
            private final ImageLoadService imageLoadService = new ImageLoadService();
            private final ObjectProperty<String> imageUrl = new SimpleObjectProperty<>();
          
            public AsyncImageProperty() {
              imageLoadService.stateProperty().addListener(new ChangeListener<State>() {
                @Override
                public void changed(ObservableValue<? extends State> observable, State oldValue, State value) {
                  if(value == State.SUCCEEDED) {
                    set(imageLoadService.getValue());
                  }
                  if(value == State.FAILED) {
                    set(null);
                  }
                  if(value == State.SUCCEEDED || value == State.CANCELLED || value == State.FAILED) {
                    String handle = imageUrl.get();
                    if(handle != null && !handle.equals(imageLoadService.imageUrl)) {
                      loadImageInBackground(handle);
                    }
                  }
                }
              });
          
              imageUrl.addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> observable, String oldValue, String value) {
                  if(!imageLoadService.isRunning()) {
                    loadImageInBackground(imageUrl.getValue());
                  }
                }
              });
            }
          
            public ObjectProperty<String> imageUrlProperty() {
              return imageUrl;
            }
          
            private void loadImageInBackground(String imageUrl) {
              synchronized(imageLoadService) {
                if(imageUrl != null) {
                  imageLoadService.setImageUrl(imageUrl);
                  imageLoadService.restart();
                }
              }
            }
          
            private static class ImageLoadService extends Service<Image> {
              private String imageUrl;
          
              public void setImageUrl(String imageUrl) {
                this.imageUrl = imageUrl;
              }
          
              @Override
              protected Task<Image> createTask() {
                final String imageUrl = this.imageUrl;
          
                return new Task<Image>() {
                  @Override
                  protected Image call() {
                    return new Image(imageUrl);
                  }
                };
              }
            }
          }
          The main reason I use this is that it hides the complexity of doing image loading in the background, and that it also works for any type of input (I use InputStreams that come from a Database and these should also be loaded in the background).
          • 2. Re: load an image in background
            MiPa
            Actually I don't know what your problem is. The code below shows that loading an image in the background does work. Just download the image given in the URL inside the code to your local harddrive and adjust the file path accordingly. Don't forget to increase the memory size of the VM because the image is large. When you then start the programm you will first see a black screen and in your console output you will see the progress when it changes. When the loading is complete the image will be shown.

            I should add that the test was done with JavaFX 2.2 build 9 on Windows 7 with JDK 7.
            package jfxfeatures.graphics.image.loading.async;
            
            import java.io.File;
            import java.net.MalformedURLException;
            
            import javafx.application.Application;
            import javafx.beans.value.ChangeListener;
            import javafx.beans.value.ObservableValue;
            import javafx.scene.Scene;
            import javafx.scene.image.Image;
            import javafx.scene.image.ImageView;
            import javafx.scene.layout.StackPane;
            import javafx.scene.paint.Color;
            import javafx.stage.Stage;
            
            public class AsyncImageDemo extends Application {
                 
                 @Override
                 public void start(Stage stage) {
                      String imgURL = null;
                      try {
                           final String remoteURL = "http://www.spacetelescope.org/static/archives/posters/large/earth02.jpg";
                           final String localURL = new File("data/earth02.jpg").toURI().toURL().toExternalForm();
                           final String localFile = "data/earth02.jpg";
                           
                           //===========================
                           // Select local or remote image source.
                           imgURL = localFile;
                           //===========================
                      } catch (MalformedURLException e1) {
                           e1.printStackTrace();
                      }
            
                      StackPane root = new StackPane();
                      Scene scene = new Scene(root, 800, 800);
                      scene.setFill(Color.BLACK);
                      
                      ImageView iv = new ImageView();
                      iv.setPreserveRatio(true);
                      iv.fitHeightProperty().bind(root.heightProperty());
                      iv.fitWidthProperty().bind(root.widthProperty());
                      root.getChildren().add(iv);
            
                      stage.setTitle(getClass().getSimpleName());
                      stage.setScene(scene);
                      stage.show();
            
                      if (imgURL != null) {
                           Image image = new Image(imgURL, true);
                           image.progressProperty().addListener(new ChangeListener<Number>() {
                                @Override
                                public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                                     System.out.println("Progress: " + newValue);
                                }
                           });
                           iv.setImage(image);
                      }
                 }
            
                 public static void main(String[] args) {
                      launch(args);
                 }
            }
            • 3. Re: load an image in background
              user8244906
              Thank you, The problem was the absolute path. With new File("E:\\P1130414.jpg").toURI().toURL().toExternalForm(); I was able to load the File correct.

              Thank you
              • 4. Re: load an image in background
                MiPa
                If an answer was helpful or correct, you should mark it as such.
                • 5. Re: load an image in background
                  956804
                  Hello,

                  In 2.2 version background load is not working poperly (javafx Image class).

                  My application is working 100% in 2.1.1 version. When I upgrated to 2.2, sometimes load sometimes do not.

                  Please guys see this for community!

                  Thank you.
                  • 6. Re: load an image in background
                    jsmith
                    How do you know that the image doesn't load? Do you monitor the image error property?

                    http://docs.oracle.com/javafx/2/api/javafx/scene/image/Image.html#errorProperty
                    • 7. Re: load an image in background
                      jmart
                      The hardest thing about loading an image from a file is locating the right path. I bet this is a path problem. If your image is in your jar, then you need to treat it as a resource.