Java Swing: Runnable JAR file does not work when including images - java

The code below works fine in Eclipse (both image-handling possibilities). But when exporting as a Runnable JAR File, and double-clicking the .JAR, nothing happens. If I comment out the image parts of the code, the .JAR runs fine as an export and the frame builds. So it seems the getting of the image is causing the .JAR to fail.
I've got the strawberry.jpg file sitting in 'C:\Users\sean\workspace\myApps\bin\testing' Could you advise if the issue is with my code?
(Code first modified here: Java Swing: unable to load image using getResource)
package testing;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
public class IconTest {
public static void main(String[] arguments) throws IOException {
JFrame frame1 = new JFrame();
frame1.setTitle("Frame1");
frame1.setSize(500, 500);
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout flo = new FlowLayout();
frame1.setLayout(flo);
//POSSIBILITY 1 TO HANDLE IMAGE
InputStream resourceAsStream = IconTest.class.getResourceAsStream("strawberry.jpg");
Image image = ImageIO.read(resourceAsStream);
JLabel label1 = new JLabel(new ImageIcon(image));
//POSSIBILITY 2 TO HANDLE IMAGE
/* java.net.URL url= IconTest.class.getResource("strawberry.jpg");
BufferedImage watermarkImage = ImageIO.read(url);
JLabel label1 = new JLabel(new ImageIcon(watermarkImage));*/
frame1.add(label1);
frame1.setVisible(true);
}
}

Put the image where you have the source file because it points to the source directory
InputStream resourceAsStream = IconTest.class.getResourceAsStream("strawberry.jpg");
and then generate runnable jar file and then right click the jar and give run as java platform binary

POSSIBILITY 3 TO HANDLE IMAGE :
You can check that resource that you are fetching is exist or not. It resource not found then you can create JLabel with alternative text also...
JLabel label1 ;
URL imageUrl = IconTest.class.getClassLoader().getResource("strawberry.jpg");
if ( imageUrl != null ) {
label1 = new JLabel(new ImageIcon(imageUrl));
} else {
label1 = new JLabel("Alternative text");
}

Following Maven standard directory layout might be helpful:

InputStream resourceAsStream = IconTest.class.getResourceAsStream("/strawberry.jpg")
It should start from "/". Also check whether the jar actually have the image. Just unpack it and check whether the image is actually added.

The guidance offered here in troubleshooting the problem helped greatly - thank you to everyone. I tested contents of an exported JAR; I used diagnostic code suggested by Kishan to determine if my code could "see" the image. I believe it might have something to do with the way Eclipse works/refreshes if I move images around in the file system instead of the Eclipse import function.
Finally, in order to get it to work, I made the following changes:
I created a new project and two sub-packages - one for 'resources' and one for my code class. Then I right-clicked > import on the resources package in Eclipse to get the image.
The only thing to change in my code is ....getResourceAsStream("/resources/strawberry.jpg");

Related

JCEF (Java Chromium Embedded Framework) Browser does not load content; only blank screen on Eclipse

I have been trying to get the Java version of Chromium Embedded Framework (JCEF) to work on Eclipse for some time. I am able to verify that the library files are working correctly, since if I run the included sample class files on the VM, the program runs and some webpage is displayed. However, if I run the program from Eclipse, the program will always display a blank window. I am able to verify that the library binary jcef_helper.exe is successfully run, but not matter how I link the .jar files and other library files, the webpage will not generate and there will always be a blank screen. I cannot pinpoint the issue here. I tried specifying path, adding the JCEF library path of my OS environment variables PATH field to no avail. I have followed the documentation, even sample files behave the same way when I have anything to do with compilation/ run. One note of interest, my Eclipse console will display this during run:
initialize on Thread[AWT-EventQueue-0,6,main]
Perhaps there is a thread issue?
Code in question:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import org.cef.CefApp;
import org.cef.CefApp.CefAppState;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.browser.CefBrowser;
import org.cef.handler.CefAppHandlerAdapter;
public class WebV
{
public static void main(String args[])
{
Dimension dispDimension = Toolkit.getDefaultToolkit().getScreenSize();
int width = (int)Math.round(dispDimension.getWidth() / 2);
int height = (int)Math.round(dispDimension.getHeight() / 2);
CefApp.addAppHandler(new CefAppHandlerAdapter(null)
{
#Override
public void stateHasChanged(CefAppState state)
{
if(state == CefAppState.TERMINATED)
{
System.exit(0);
}
}
});
CefSettings settings = new CefSettings();
settings.windowless_rendering_enabled = false;
CefApp cefApp = CefApp.getInstance(settings);
CefClient client = cefApp.createClient();
CefBrowser browser = client.createBrowser("http://www.google.com", false, false);
Component browserComponent = browser.getUIComponent();
JFrame frame = new JFrame();
frame.setTitle("WebV");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(width, height);
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.add(browserComponent);
frame.setVisible(true);
}
}
Tested with both Java 17 and Java 8.
Run on Eclipse, with VM args:
-Djava.library.path=./bin/lib/win64
Any inupt would be greatly appreicated.
This answer was kindly provided by 'Yanovsky' at the JCEF forums.
The simple example provided by the JCEF package is incomplete.
We need to add a CefMessageRouter instance to our browser client. This is demonstrated in the detailed examples, but not the simple one. This code should be added before we create our CefBrowser instance and after we have created a CefClient object:
CefMessageRouter msgRouter = CefMessageRouter.create();
msgRouter.addHandler(new MessageRouterHandler(), true);
msgRouter.addHandler(new MessageRouterHandlerEx(client), false);
client.addMessageRouter(msgRouter);
For reference, this is my post in the JCEF forum:
https://magpcss.org/ceforum/viewtopic.php?f=17&t=18834&sid=45381db639d1621f2f8b38b4d8848800
I just copied and pasted your code in eclipse and added the jars and ran the code and voila, google.com opened without any issues.
I didnt have to add any more new lines as suggested by mindoverflow.
The webpage was visible in the window after a few secs and not immediately.
Here's what popped up after running the code.
And in the eclipse console, I see this
initialize on Thread[AWT-EventQueue-0,6,main] with library path C:\path\to\dlls

Cannot delete external JAR file after loading in Image [duplicate]

This question already has answers here:
file.delete() returns false even though file.exists(), file.canRead(), file.canWrite(), file.canExecute() all return true
(17 answers)
Closed 2 years ago.
I am currently busy with building a simple javafx application. In this application, you can add and remove .jar files from within the application, from which I am gathering some information. One of the things I use from these .jar files are textures stored as images.
Whenever I load an Image using a path from the jar file, I am unable to remove this .jar file later on. This is quite logical as the .jar file is now being used by this Image, but for some reason, I am unable to delete the .jar file from within the application even when removing all references to this Image and calling the garbage collector.
The way I am currently trying to delete the file is the following:
File file = new File("mods/file.jar");
file.delete();
At some point in the application I initialize the image as follows:
Image block = new Image(pathToJar);
I have tried the following things to resolve my problem:
Set block = null; and call System.gc();
Call Image.cancel() and call System.gc();
I have also tried the above in combination with System.runFinalization();
I tried removing the .jar file when the stage is closing in hopes of everything being unloaded, but without success.
At this point in time, I am not quite sure why I am unable to actually delete the .jar file. Could anyone possibly explain to me why this is the case and how it could be resolved? Many thanks in advance!
EDIT: the purpose of the application was not clear enough. I am making a color picker that takes average colors of textures from .jar files (Minecraft mods). These .jar files are to be added and deleted from the application in a flexible way. Once you do not want to consider textures of a certain .jar file anymore, you just remove it from the application and be done with it. For ease of use, I made copies of the .jar files so I can access them relatively. Once you are done with the .jar file I want to remove this copy as it will just take in unnecessary storage.
I have narrowed the problem (thus far) down to the initialization of an Image. On request, here a MRE:
public class example extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
// Read image, needed at some point in my code
Image block = new Image("jar:File:./mods/botania.jar!/assets/botania/textures/blocks/alfheim_portal.png");
// Make it so that jar is not used anymore
block.cancel();
block = null;
System.gc();
// Try to delete the file after being done with it
File delete = new File("mods/botania.jar");
Files.delete(delete.toPath());
}
}
After initializing the image, and thereafter removing references to it, it should be cleaned by the garbage collector (at least to my knowledge). Instead, now it just gives the following error:
Caused by: java.nio.file.FileSystemException: mods\botania.jar: The
process cannot access the file because it is being used by another
process.
I can't reproduce the issue on my system (Java 14 on Mac OS X); however running it on Windows 10 with the same JDK/JavaFX versions produces the exception you describe.
The issue appears to be (see https://stackoverflow.com/a/54777849/2067492, and hat-tip to #matt for digging that out) that by default the URL handler for a jar: URL caches access to the underlying JarFile object (and doesn't call close(), even if an InputStream obtained from it is closed). Since Windows holds on to file handles in those situations, the underlying OS is unable to delete the jar file.
I think the most natural way to address this is to use the java.util.jar API (or just the plain java.util.zip API), which will give you far more control over closing resources than generating a URL and passing the URL to the Image constructor.
Here's a self-contained example using this approach, which works both on my Mac and on my Windows 10 virtual VM:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import javax.imageio.ImageIO;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void init() throws Exception {
// create an image in a jar file:
BufferedImage image = new BufferedImage(100, 100, ColorSpace.TYPE_RGB);
Graphics graphics = image.getGraphics();
graphics.setColor(new Color(0xd5, 0x5e, 0x00));
graphics.fillRect(0, 0, 100, 100);
graphics.setColor(new Color(0x35, 0x9b, 0x73));
graphics.fillOval(25, 25, 50, 50);
JarOutputStream out = new JarOutputStream(new FileOutputStream("test.jar"));
ZipEntry entry = new ZipEntry("test.png");
out.putNextEntry(entry);
ImageIO.write(image, "png", out);
out.close();
}
#Override
public void start(Stage stage) throws Exception {
assert Files.exists(Paths.get("test.jar")) : "Jar file not created";
JarFile jarFile = new JarFile("test.jar");
JarEntry imgEntry = jarFile.getJarEntry("test.png");
InputStream inputStream = jarFile.getInputStream(imgEntry);
Image img = new Image(inputStream);
jarFile.close();
// The following line (instead of the previous five lines) works on Mac OS X,
// but not on Windows
//
// Image img = new Image("jar:file:test.jar!/test.png");
Files.delete(Paths.get("test.jar"));
assert ! Files.exists(Paths.get("test.jar")) : "Jar file not deleted";
ImageView iview = new ImageView(img);
Scene scene = new Scene(new BorderPane(iview), 200, 200);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}

Display an image in java

public void loadStdImage() throws IOException
{
Image image = ImageIO.read(this.getClass().getResource("/Resources/Images/Student/Capture.png")); //Line 350
ImageIcon icon = new ImageIcon(image);
JLabel lblImage = new JLabel(icon);
lblImage.setIcon(icon);
lblImage.setBounds(753, 50, 149, 171);
add(lblImage);
}
I tried many things... but nothing works out. Continuously showing the following run-time error
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(Unknown Source)
at View.Student.loadStdImage(Student.java:350)
Project folder structure is:
edit:
Found the solution. See the change of icon of the resource folder in the following picture and the above image. I added my resource folder to Java Build Path. Right click on your project, go to properties, then select 'Java Build Path', from there add your folder to java build path.
Cheers
enter image description here
welcome to SO. As you are new here, please read this - https://stackoverflow.com/help/mcve
Let me help you with this for now.
I have standard Eclipse project:
and my test class looks like (minimal):
package q34460547;
import java.awt.Image;
import java.io.IOException;
import javax.imageio.ImageIO;
public class LoadTest {
public static void main(String[] args) throws IOException {
new LoadTest().loadStdImage();
}
public void loadStdImage() throws IOException {
Image image = ImageIO.read(this.getClass().getResource("/ScreenShot005.png"));
}
}
and now, when I used
ImageIO.read(this.getClass().getResource("/ScreenShot005.png"));
image is loaded from res so called source folder in Eclipse.
When I used
ImageIO.read(this.getClass().getResource("ScreenShot005.png"));
image s loaded from the folder in which LoadTest.java file is (to be precise it is also compiled to same folder - in Eclipse it's bin).
You can find more info for example here - What is the difference between Class.getResource() and ClassLoader.getResource()?
edit:
The image has to be on classpath (when using Class.getResource), that's why it was not loaded from Resources folder. There are two options, use another version of ImageIO.read() or make your Resources folder a source folder:

Eclipse refer to image

So i am new to Java and this will probaly the easiest question you will ever see, still I can not find the anser on the internet.
I want to set the icon of my program, This code does works:
frame.setIconImage(Toolkit.getDefaultToolkit().getImage("MYPROBLEM"));
Yet i can not get the path correct at the MYPROBLEM section. This is my structure:
Projectname
-src
--default package
---myfunctions
--test <----a map
---icon.png
Whenever i replace MYPROBLEM with src/test/icon.png it does work. however when i export my application as jar the default Java icon shows up. Replacing MYPROBLEM with something like test/icon.png does also not works.
I do appologise for my English. Bear with me because I am a newbie ;)
This will load an image from the classpath.
Image image = new ImageIcon(this.getClass().getResource("MYPROBLEM")).getImage();
frame.setIconImage(image);
for some reason sometimes it does not work but what you can do is to add the full path of the location of the image. here is an example
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JFrame;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class JFrameIcon {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(300, 150);
frame.setTitle("tutorialData.com");
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setAlwaysOnTop(true);
frame.setIconImage(Toolkit.getDefaultToolkit().getImage("C:\\Users\\Sirnurpc\\Desktop\\icon.png"));
frame.setVisible(true);
}
}
reference seticon
In your case if you are using Netbeans then the location would be
C:\Users\yourloginname\Documents\NetBeansProjects\yourproject\imagename.png
And for Eclipse which I am guessing you are using would be something like this
C:\Users\yourlogingname\workspace\yourproject\imagename.png

Trying to import my own packages

package mainClasses;
/*
* Frame Info and all that ****,
* mainFrame is the actual frame itself
* it will refer to MainC.java a lot Main class = Main Class
*/
import java.awt.FlowLayout;
import java.awt.Graphics;
import JavaGame.src.resources.*; //Problem Code
import javax.swing.JButton;
import javax.swing.JFrame;
public class mainFrame extends JFrame {
private static final long serialVersionUID = 1L;
public mainFrame() {
JButton playButton = new JButton();
JButton infoButton = new JButton();
JButton exitButton = new JButton();
int x = 300, y = 300;
setSize(x, y);
setVisible(true);
setLayout(new FlowLayout());
setTitle("Kingdom Raider");
setDefaultCloseOperation(EXIT_ON_CLOSE);
/*Buttons and Properties*/
playButton.setBounds(x, y, 200, 100);
playButton.setText("Play!");
add(playButton);
infoButton.setBounds(x, y, 200, 100);
infoButton.setText("Information");
add(infoButton);
exitButton.setBounds(x, y, 200, 100);
exitButton.setText("Exit");
add(exitButton);
/* Add image here */
}
public void Painting (Graphics g) {
//Me.
}
}
I'm creating a game and I'm having an import problem.
As you can see I want to import JavaGame.src.resources, as I'm trying to import an img.
Here's how my Directory stands:
I don't need to know the code on resourcesmanager.java its blank at the moment.
So basically, this class here is in packages mainClasses, but i want to access the resources package. What gives?
Your package name is resources, so write this:
import resources.*; // No-Problem Code
The remaining parts of the directory structure is specific to Eclipse and doesn't have anything to do with Java classpaths
Your source folder is src, so this is the root of your class hierarchy. You should do
import resources.*
However using * is bad form and you should try and import only classes that you need in this particular class, like you've done with javax.swing.JButton for example. So:
import resources.ResourceManager;
Resources aren't imported like packages. Have a look here: http://docs.oracle.com/javase/1.5.0/docs/guide/lang/resources.html.
Specifically, here's an example how to load images from resources: http://docs.oracle.com/javase/tutorial/uiswing/components/icon.html#getresource.
Eclipse will automatically import stuff for you if you copy and paste something-maybe you could write a short clip that uses something in JavaGame.src.resources, and then copy paste that-eclipse will do the rest.
I think this could be a problem with Eclipse configuration. Sometimes Eclipse considers the source folder in the project as part of the package. Just delete the project from the Eclipse workspace without deleting it from the file system and import it again.
That should help.
Deleting project from eclipse without deleting it from the file system:
http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.user%2Ftasks%2Ftasks-42b.htm
Importing existing project into eclipse:
http://agile.csc.ncsu.edu/SEMaterials/tutorials/import_export/
What you want to do is access the files stored in your resources folder. To do this, you don't import the folder as you tried to do. Instead, do what Tony the Pony advised and use
getResource("FileName.ext")
As an example, to turn a file into an icon, you'll have to use the resource path:
java.net.URL path = this.getClass().getResource("FileName.jpg");
ImageIcon icon = new ImageIcon(path);
I should also point out that if you're using NetBeans, you need to add the resource folder as a source folder; otherwise the project won't compile how you want it to, resulting in a .jar file that can't access the resource files. Eclipse might be similar. To add the folder as a source:
Right click on project
Select properties
Click "Sources" in categories pane
Click "Add Folder" and select the resource folder you made

Categories

Resources