Unable to locate/open image inside exported jar - java

I have explored every single solution related to this problem on Stack Overflow, and the solutions I encountered worked only in my IDE (Eclipse Mars), but when exported they all failed.
I have an image file I simply want to load from inside my exported jar.
As you can see from the project layout, Images is a folder directly inside of the project folder CooldownTrackerJava. To refer to it, I've tried a variety of methods.
//My class' name is AddItemDialog
//Method 1
String filePath = File.separator + "Images" + File.separator + "questionMark.png";
InputStream inputStream = AddItemDialog.class.getResourceAsStream(filePath);
BufferedImage img = ImageIO.read(inputStream);
I tried method 1 in a few ways. I tried it with and without the File.separator at the start of the filePath. I understand that the former refers to an absolute path, while the latter is relative. I also tried moving the Images folder inside of the directory where my class files were.
All of these failed giving me a NullPointerException when exported and tested multiple times.
//Method 2
String saveLocation = File.separator + "Images" + File.separator + "questionMark.png";
Image img = Toolkit.getDefaultToolkit().getImage(getClass().getResource(saveLocation));
As per this post I tried the above method however it still did not work.
I've tried many variations aside from the ones mentioned in this post but none of them have been successful when I exported the jar.
Do I need to add the Images folder to my build path? Should I move it to the src folder? Am I missing one obvious step? All suggestions would be highly appreciated. Also here is the layout of the exported jar file.

The solution was a two-part effort. Firstly, I moved my Images folder into the src directory as shown below. Kudos to Matthew.
I then removed File.separator and replaced it with a forward slash/. Thanks to fge.
Do not use File.separator(). Separators for resource paths on the class path is always /. If you use Windows you will therefore always get the wrong result.
I used a variant of method 1 to test it. Both methods will work though.
String saveLocation = "/Images/questionMark.png";
InputStream inputStream = this.getClass().getResourceAsStream(saveLocation);
try {
BufferedImage img = ImageIO.read(inputStream);
} catch (IOException e) {
e.printStackTrace();
}

Related

How to get .jar resources path?

I'm using a custom method to get pictures from the resources/ folder. The hardcoded path works well when programming during production (src/main/resources/). However when delivering, I would need to make this path relative to the .jar root. So I made this.
public static Image getImageFromFile(String file)
{
Image image = null;
try
{
String path = FileUtils.class.getClassLoader().getResource(file).toExternalForm();
System.out.println(path);
File pathToFile = new File(path);
image = ImageIO.read(pathToFile);
}
catch (IOException ex) {ex.printStackTrace();}
return image;
}
file:/C:/Users/Hugo/Desktop/Hugo/Java%20Workspace/ClashBot/bin/main/icons/level-label.png
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at com.lycoon.clashbot.utils.FileUtils.getImageFromFile(FileUtils.java:55)
The printed path is valid and points to the corresponding picture. However, the program raises an IOException.
Why can't it find the file?
You're jumping through way too many hoops. It's quite simple:
FileUtils.class.getResource("path.png");
// -OR-
try (var in = FileUtils.class.getResourceAsStream("path.png")) {
// in is an inputstream.
}
is all you need. Note that this means the path.png file is searched for in the exact same place (and even same 'subdir') as where FileUtils lives. So if you have, say, a file on C:\Projects\Hugo\MyApp\myapp.jar, and if you were to unzip that, inside you'd find com/foo/pkg/FileUtils.class, then the string path.png would look in that jar, and for com/foo/pkg/path.png. In other words, AnyClass.class.getResource("AnyClass.class") will let a class find its own class file. If you want to go from the 'root' of the jar, add a slash, i.e. FileUtils.class.getResource("/path.png") looks in the same jar, and for /path.png inside that jar.
getResource returns a URL. getResourceAsStream returns a stream (which you need to close; use try-with-resources as I did). Just about every resource-using API out there will take one of these two as input. For example, ImageIO does so; it even takes a URL so you can use either one:
var image = ImageIO.read(FileUtils.class.getResource("imgName + ".png"));
Yes. It's a one-liner. This will load images straight from within a jar file!
You could try to use a slightly different call like this:
java.net.URL fileUrl = Thread.currentThread().getContextClassLoader().getResource(file);
String filePath = URLDecoder.decode(fileUrl.getPath(), "UTF-8");
image = ImageIO.read(filePath);

Having problems with packaging images into a jar file

I have scoured this site, and been looking over solutions on how to fix this, and none have given a solution that changes the error occurring. I cannot pinpoint what the problem is. None of the similar questions regarding this have helped.
I'll start with the code I have
public static BufferedImage getImage(String uri) throws IOException {
BufferedImage image = null;
image = ImageIO.read(ImageLoader.class.getResource(uri));
return image;
}
And where I call the method
try {
sprite = ImageLoader.getImage("images/testSprite.png");
} catch (IOException e) {
e.printStackTrace();
}
The error returned is IllegalArgumentException input == null on the ImageIo.read line in the original method.
To preface, I have tried every imaginable file naming sequence. I tried it including res, the name of my resource folder (both with and without a slash at the beginning), I tried it with a slash preceding images, the folder that contains the image I'm trying to access, and simply the name of the image, again, with and without the slash.
I used Eclipse's "Build Path" to create my res folder in the Project folder, but if I look at the .zip, it doesn't contain the folders I included, even the src folder, but it does contain all of the class files from the src folder. I'm confused why this is happening.
I would really like some insight on what exactly I am doing wrong here.
EDIT: After trying nearly everything imaginable, I finally figured it out. The folder needs to be created as a Package, and the image needs to be placed within the package. A source folder or normal folder doesn't seem to be picked up by the compiler. Just add a package to your source folder for the image to be loaded.

windows - User folder with special character -> class.getResource returns null [duplicate]

The getResourceAsStream-method returns null whenever running the executable jar in a directory which ends with a exclamation mark.
For the following example, I have a Eclipse project the following directory structure:
src\ (Source Folder)
main\ (Package)
Main.java
res\ (Source Folder)
images\
Logo.png
I'm reading the Logo.png as follows:
public static void main(String[] args) throws IOException {
try (InputStream is = Main.class.getClassLoader().getResourceAsStream("images/Logo.png")) {
Image image = ImageIO.read(is);
System.out.println(image);
}
}
See the attachment for 2 test cases. First, the executable jar is started from the directory "D:\test123!##" without any problems. Secondly, the executable jar is started from the directory "D:\test123!##!!!", with problems.
Are directories ending with an exclamation mark not supported? Is the code wrong?
Thanks in advance.
Probably because of this bug or any of the many similar bugs in the Java bug database:
http://bugs.sun.com/view_bug.do?bug_id=4523159
The reason is that "!/" in a jar URL is interpreted as the separator between the JAR file name and the path within the JAR itself. If a directory name ends with !, the "!/" character sequence at the end of the directory is incorrectly interpreted. In your case, you are actually trying to access a resource with the following URL:
jar:file:///d:/test1231##!!!/test.jar!/images/Logo.png
The bug has been open for almost 12 years and is not likely to be fixed. Actually I don't know how it can be fixed without breaking other things. The problem is the design decision to use ! as a character with a special meaning (separator) in the URL scheme for JAR files:
jar:<URL for JAR file>!/<path within the JAR file>
Since the exclamation mark is an allowed character in URLs, it may occur both in the URL to the JAR file itself, as well as in the path within the JAR file, making it impossible in some cases to find the actual "!/" separator.
A simple work around for Windows is to use "\" instead of "/" in the path. That would mean the "!/" character sequence is found after the full path. For instance:
new URL("jar:file:\\d:\\test1231##!!!\\test.jar!/images/Logo.png");
My Code:
File jar = new File(jarPath + "/" + jarName);
URL url = new URL("jar:" + jar.toURI() + "!" + dataFilePath);
InputStream stream = null;
try {
stream = url.openStream();
} catch (FileNotFoundException e) {
// Windows fix
URL urlFix = new URL("jar:" + jar.toURI().toString().replace('/', '\\')
+ "!" + dataFilePath);
stream = urlFix.openStream();
}
I use toURI() because it handles things like spaces.
Fixes:
The fix itself would be for Java to check if the file exists and if not continue to the next separator (the "!/" part of the url) until the separators are exhausted, then throw the exception. So it would see that "d:\test1231##!!" throws a java.io.FileNotFoundException and would then try "d:\test1231##!!!\test.jar" which does exist. This way it does not matter if there are "!" in the file path or in the jar's files.
Alternatively the "!/" can be switched to something else that is an illegal file name or to something specific (like "jarpath:").
Alternatively make the jar's file path use another parameter.
Note:
It may be possible to override something, swap a handler, or change the code to open the file first then look inside the jar file later but I have not looked.

Executing jar issue - uncaught error fetching image

I've made an audio player and the jar was made with netbeans. To load the images I've used:
ClassLoader cl = this.getClass().getClassLoader();
URL playerIconURL = cl.getResource("tp/audioplayer/Images/icon.png");
if (playerIconURL != null){
ImageIcon playerIcon = new ImageIcon(playerIconURL);
frame.setIconImage(playerIcon.getImage());
}
else{
System.err.println("cannot load player icon");
}
I mention that the folder Images is in the src/tp/audioplayer.
When I'm running the application inside netbeans everything is allright, but when I execute the jar in command prompt,the application starts but it's blank and it blocks and I get:
Can you tell me what I've done wrong or what is the problem? Thanks in advance!
If tp is in your classpath you will have to load it with cl.getResource("/tp/audioplayer/Images/icon.png") if tp is NOT a source folder (but still added to the buildpath.
If you add tp as a sourcefolder then
cl.getResource("/audioplayer/Images/icon.png")
Note that jars are casesensitive, make sure you the case-sensitive file-path.
Try any of these:
// using getResourceAsStream
InputStream is = this.getClass().getResourceAsStream( "picture.gif" );
// or
InputStream is = MyClass.class.getResourceAsStream( "stuff.ser" );
// or
InputStream is = MyApp.class.getClassLoader().getResourceAsStream( "InWords.properties" );
The resource in the jar file must be qualified with same package name as the class you call getResourceAsStream from. Alternatively, you can use an absolute name beginning with a / where dots get mapped to /s. If you don’t have a lead /, you have a relative name, and the name of the package will be prepended. If you use a /, you must include the name of the package yourself, or whatever name the resource is filed under in the jar.
For example you could specify /com/mindprod/mypackage/mystuff.ser or /com.mindprod.mypackage.mystuff.ser or simply mystuff.ser. Don’t use Windows style filenames with . These are not filenames, but Java resources that live along with the class files either in jars or sometimes freestanding on disk, or on the server.
In theory, getResourceAsStream will look in the local classpath, in the jar and in the directory where the class file was loaded from.

How to set icon image for swing application?

I've seen many different examples showing how to set a JFrame's IconImage so that the application uses that icon instead of the standard coffee mug. None of them are working for me.
Here's "my" code (heavily borrowed from other posts and the internet at large):
public class MyApp extends JFrame
{
public MyApp()
{
ImageIcon myAppImage = loadIcon("myimage.jpg");
if(myAppImage != null)
setIconImage(myAppImage.getImage());
}
private ImageIcon loadIcon(String strPath)
{
URL imgURL = getResource(strPath);
if(imgURL != null)
return new ImageIcon(imgURL);
else
return null;
}
}
This code fails down in loadIcon when making a call to the getResource() method. To me, there's only 2 possibilities here: (1) the myImage.jpg is in the wrong directory, or (2) getResource() doesn't like something about my image (I had to convert it from CMYK to RGB in Photoshop so I could use the same image elsewhere with ImageIO.)
I have used the System.out.println(new File(".").getAbsolutePath()); trick to locate the directory where the image JPG should be stored, and still nothing worked. I have subsequently placed the JPG in just about every directory inside my project, just to rule file location out as the culprit.
So that leaves me to believe there's something that getResource() doesn't like about the JPG itself. But I have now already exhausted my understanding of images and icons in the mighty, wide world of Swing.
My JPG loads fine in other image viewers, so that's ruled out as well. Anyone have any ideas?
Thanks in advance!
I have tried following which was a answer for same kind of question like yours. And it works for me.
Try putting your images in a separate folder outside of your src
folder. Then, use ImageIO to load your images. (answered Aug 27 '13 at 0:18
AndyTechGuy)
frame.setIconImage(ImageIO.read(new File("res/icon.png")));
put the image in the root of the classpath and say getResource("classpath:myimage.jpg");
The problem with your code is that jvm is unsure where to lookup the image file so its returning null.
Here is a nice link about classpath
It should be
if(imgURL != null)
^
instead of
if(imgURL !- null)
and
URL imgURL = this.getClass().getResource(strPath);
instead of
URL imgURL = getResource(strPath);
Then it works fine, if "myimage.jpg" is in the same dir with MyApp.class
Two suggestions:
Try using the getClass().getResource("x.jpg"), and putting the file directly in the same folder as the .class file of the class you are in.
Make sure the name is identical in case - some operating systems are case sensitive, and within a JAR, everything is case sensitive.
You can try to use a "/" before your filename.
getClass().getResource("/myimage.jpg")
If you look into your build-output folder (target) you can look for your class where you are trying to get your resource from.
Your resources will probably be copied in some folders above.
For example your target directory could look like this:
target
|- de.example.app
|- Main.class
|- Main-x.y.z.jar
|- myimage.jpg
So if you just go for getClass().getResource("myimage.jpg") it will look under the folder target/de/example/app and won't find a jpg there.
You need to tell him that you want to look under the root-folder (target/**). That's why you need to place a "/" before your file.

Categories

Resources