harlekintiger
harlekintiger

Reputation: 417

javafx - load image from within a jar

I'm sorry for asking such a beginner question, but I just can't get it to work and I can't find the answer anywere either.
I want to have an image inside my .jar file and load it. While that sounds simple, I was only able to load an image while running from inside the IDE but not anymore after making the .jar (Thanks to google I was able to get the .png inside the .jar). Here is what I tried:

    BorderPane bpMain = new BorderPane();
    String fs = File.separator;

    Image imgManikin;
    try {
        imgManikin = new Image(
                Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().toString()+"\\manikin.png");
        bpMain.setBottom(new Label(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().toString()+"\\manikin.png"));
    } catch (URISyntaxException e) {
        imgManikin = new Image(
                Main.class.getProtectionDomain().getCodeSource().getLocation().getPath()+"\\manikin.png");
        System.out.println(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath()+"\\manikin.png");
        bpMain.setBottom(new Label(Main.class.getProtectionDomain().getCodeSource().getLocation().getPath()+"\\manikin.png"));
    }
    //Image imgManikin = new Image("file:src\\manikin.png");
    ImageView imgvBackground = new ImageView(imgManikin);
    imgvBackground.setFitWidth(100);
    imgvBackground.setPreserveRatio(true);
    bpMain.setCenter(imgvBackground);


    primaryStage.setTitle("Kagami");

    primaryStage.setScene(new Scene(bpMain, 300, 275));
    primaryStage.show();

Needlessly to say it didn't work. It is showing me the Label at the bottom with the path just as intended, but it seams like the path just isn't right. (I also tried using the File.seperator instead of \\ and even /, but I got the same result every time: It showes me the path but won't load the image.
I'm using Windows 7, the IDE is IntelliJ and I have the newest Java update.

Upvotes: 2

Views: 5425

Answers (2)

hotzst
hotzst

Reputation: 7526

If the jar file is on the classpath of your application and the image to be loaded is located at the root of the jar file, the image can be loaded easily by:

URL url = getClass().getResource("/manikin.png");
BufferedImage awtImg = ImageIO.read(url);
Image fxImg = SwingFXUtils.toFxImage(awtImg, new Image());
Image fxImgDirect = new Image(url.openStream());

While ImageIO returns a BufferedImage this can be converted to a fx Image using the SwingUtils. However the preferred way is to directly create a new Image instance using the InputStream from the URL.

See also Load image from a file inside a project folder. If done right it does not matter if it is loaded from a jar file or the local file system.

Upvotes: 2

Jeffrey
Jeffrey

Reputation: 44808

The Image::new(String) constructor is looking for a URL. It is possible to construct a URL for a resource in a jar file, but it's much easier to use ClassLoader::getResource or ClassLoader::getResourceAsStream to manage that for you.

Given the file structure:

   src/
      SO37054168/
          GetResourceTest.java
      example/
          foo.txt

The following, packaged as a jar will output

package SO37054168;

public class GetResourceTest {
  public static void main(String[] args) {
    System.out.println(GetResourceTest.class.getClassLoader().getResource("example/foo.txt"));
    System.out.println(GetResourceTest.class.getClassLoader().getResourceAsStream("example/foo.txt"));
  }
}

jar:file:/home/jeffrey/Test.jar!/example/foo.txt
sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@7f31245a

Note how the URL for the resource is not the same as the URL you were trying to construct. The protocol is different, and you need to have the ! after the path to the jar file.

Upvotes: 1

Related Questions