nus-cs2103-AY1920S1 / forum

Forum
1 stars 1 forks source link

Reading an image file in the same directory as the jar file #150

Closed ChangUo79 closed 4 years ago

ChangUo79 commented 4 years ago

Please read up on how to write a good question

Environment

Describe your development environment

Issue

I am trying to implement a function to add an image to a profile of a person. Currently, I am retrieving the image files through the resources/images/ directory. What I am trying to implement allows the user to add/edit the profile image by choosing their own image files that is in a folder images that is in the same directory as the jar file generated. I am having issues getting this to work. I have tried looking for solutions online but it doesn't seem to work.

Example: image

image

Code/Log Trace

For the first image, the way I retrieved my images is shown as:

private static final String IMAGE_DIRECTORY = "/images/";

    public Photo(String image) {
        requireNonNull(image);
        checkArgument(isValidFilePath(image), MESSAGE_CONSTRAINTS);
        value = image;
        photo = new Image(this.getClass().getResourceAsStream(IMAGE_DIRECTORY + image));
    }

The second image is my attempt to retrieve an image file in the images folder.

public Photo(String image) {
        requireNonNull(image);
        checkArgument(isValidFilePath(image), MESSAGE_CONSTRAINTS);
        value = image;
        File imageFile = new File(IMAGE_DIRECTORY + value);
        photo = new Image(imageFile.toURI().toString());
    }
geshuming commented 4 years ago

Have you checked if the photo is actually created, and that no errors were raised and dropped by the AddressBook?

I suspect that the URI does not actually translate into URL. Otherwise, I think it might be due to the lack of escape slashes in the string.

shaoyi1997 commented 4 years ago

In the second case, File imageFile = new File(IMAGE_DIRECTORY + value); assumes that the given path starts from the project root directory (i.e. starting from main/...). However, your image is actually stored in the resource folder, which is not the root level directory. The first case works because getResourceAsStream reads a file from src/main/resources.

You might want to consider letting your IMAGE_DIRECTORY = src/main/resources/images/ for the time being, while still running in the IDE. This will allow new File(IMAGE_DIRECTORY + value) to get the file from the root directory.

ChangUo79 commented 4 years ago

In the second case, File imageFile = new File(IMAGE_DIRECTORY + value); assumes that the given path starts from the project root directory (i.e. starting from /main/...). However, your image is actually stored in the resource folder, which is not the root level directory. The first case works because getResourceAsStream reads a file from src/main/resources.

You might want to consider letting your IMAGE_DIRECTORY = src/main/resources/images/. This will allow new File(IMAGE_DIRECTORY + value) to get the file from the root directory.

But what if the jar file isn't inside the project directory and moved to another directory with an images folder? For example, i moved the jar file to Documents and there is an images folder. How then would I retrieve the images?

j-lum commented 4 years ago

But what if the jar file isn't inside the project directory and moved to another directory with an images folder? For example, i moved the jar file to Documents and there is an images folder. How then would I retrieve the images?

First, understand that files that are packaged in your jar file has to be accessed in a certain way (getResource). Files outside your jar can be accessed as usual.

shaoyi1997 commented 4 years ago

But what if the jar file isn't inside the project directory and moved to another directory with an images folder? For example, i moved the jar file to Documents and there is an images folder. How then would I retrieve the images?

Ah I see! I suspect your solution would work if the jar file is actually the case as you mentioned. However, if you are still running from your IDE, this method would break down since new File(...) will attempt to read from the root project directory.

Have you tried building the jar file and manually testing to see if it works?

ChangUo79 commented 4 years ago

Ah I see! I suspect your solution would work if the jar file is actually the case as you mentioned. However, if you are still running from your IDE, this method would break down since new File(...) will attempt to read from the root project directory.

Have you tried building the jar file and manually testing to see if it works?

i built the jar file with an images folder and the relevant images in the Documents directory but it doesn't seem to work.

ChangUo79 commented 4 years ago

First, understand that files that are packaged in your jar file has to be accessed in a certain way (getResource). Files outside your jar can be accessed as usual.

I understand files in my jar file is accessed via getResource. So how should i access files outside of my jar in this case?

kenneth-fung commented 4 years ago

I understand files in my jar file is accessed via getResource. So how should i access files outside of my jar in this case?

Maybe try doing it the same way as storage? Storage creates a data folder in the same directory as the jar file.

shaoyi1997 commented 4 years ago

i built the jar file with an images folder and the relevant images in the Documents directory but it doesn't seem to work.

I examined your code further and realised that your IMAGE_DIRECTORY = /images/ instead of images/. Placing a leading slash makes the path an absolute file path instead of a relative path, thus this references to C:/images/ (assuming you're using Windows), instead of C:/path/to/jar/folder/images/.

In addition, new Image(path) requires path to start with file:// in order to load the image through ImageView.

Hence, to sum up, you might want to try the following changes:

I've tried these changes on my end and it works through the jar file. Hope it works for you as well! :)

ChangUo79 commented 4 years ago

i built the jar file with an images folder and the relevant images in the Documents directory but it doesn't seem to work.

I examined your code further and realised that your IMAGE_DIRECTORY = /images/ instead of images/. Placing a leading slash makes the path an absolute file path instead of a relative path, thus this references to C:/images/ (assuming you're using Windows), instead of C:/path/to/jar/folder/images/.

In addition, new Image(path) requires path to start with file:// in order to load the image through ImageView.

Hence, to sum up, you might want to try the following changes:

* `IMAGE_DIRECTORY = images/`

* `new Image("file://" + imageFile.toURI().getPath())`

I've tried these changes on my end and it works through the jar file. Hope it works for you as well! :)

Thank you so much! Definitely working now. Really appreciate the help from everyone! Just one more question. Will this work only with jar files? I tried it in the IDE and the images dont show up. I imagine I will need to switch between methods depending on whether I'm working on it in the IDE or the jar file.

shaoyi1997 commented 4 years ago

Thank you so much! Definitely working now. Would this work with the IDE or only for jar files?

Glad to hear it works!

It should be able to work in the IDE as well, provided you have an images folder in your root project directory i.e. main/images/. You can specify this folder in .gitignore so that it won't be pushed into the remote repo.

Additionally, note that your application does not automatically create an images folder in the root directory, so you might want to consider automatically creating this folder when your user launches the app to aid your user.

ChangUo79 commented 4 years ago

Thank you so much! Definitely working now. Would this work with the IDE or only for jar files?

Glad to hear it works!

It should be able to work in the IDE as well, provided you have an images folder in your root project directory i.e. main/images/. You can specify this folder in .gitignore so that it won't be pushed into the remote repo.

Additionally, note that your application does not automatically create an images folder in the root directory, so you might want to consider automatically creating this folder when your user launches the app to aid your user. Will take note of it. Thanks again for the help!

damithc commented 4 years ago

Thanks everyone who pitched in. Kudos to @shaoyi1997 for guiding the issue to a successful resolution 👏

ChangUo79 commented 4 years ago

Hello again! A new issue has arise after the previous issue was solved. Currently many of my test cases are failing due to this line photo = new Image("file://" + imageFile.toURI().getPath()); for some reason. From what I know, there is some initialization problem and there is trouble getting the images.

Some screenshots of the exceptions and errors: image image

I tried looking for similar issue and came upon this: https://bugs.openjdk.java.net/browse/JDK-8093075 The latest reply from the link says that this issue will not be fixed. Does anyone know any way around this problem? Greatly appreciate the help!

shaoyi1997 commented 4 years ago

Hi!

I suspect the bulk of these errors goes down to the failure to initialize Photo. More specifically, this RuntimeException: java.lang.RuntimeException: Internal graphics not initialized yet.

In Photo.java, you are initializing photo with type Image, which is a JavaFX component that depends on the JavaFX toolkit. This adds dependency for the JavaFX library right from the lower level classes. Thus, in unit testing, the JavaFX toolkit is not set up since only classes that extend Application (or subclasses of these classes) will start up the toolkit but here, only MainApp.java extends Application. Hence, Image photo cannot be initialized.

Perhaps you can let the Photo class have an instance variable that contains the file path of the image file, then instantiate the Image within the Ui component using this file path!

ChangUo79 commented 4 years ago

Hi!

I suspect the bulk of these errors goes down to the failure to initialize Photo. More specifically, this RuntimeException: java.lang.RuntimeException: Internal graphics not initialized yet.

In Photo.java, you are instantiating photo with type Image, which is a JavaFX component that depends on the JavaFX toolkit. This adds dependency to the JavaFX library right from the lower level classes. Thus, in unit testing, the JavaFX toolkit is not set up since only classes that extend Application (or subclasses of these classes) will start up the toolkit but here, only MainApp.java extends Application. Hence, Image photo cannot be instantiated.

Perhaps you can let the Photo class have an instance variable that contains the file path of the image file, then instantiate the Image within the Ui component using this file path!

Genius! Test cases have all passed. Thanks again for your help!