How to include and access images in a .jar - java

I want to package images in an executable .jar file in Eclipse, but even after storing them and linking to them, they do not seem to show up. I am trying to follow this guide as it seems to be the closest to what I am trying to do.
From my understanding, I need to read each of the 4 image files as a BufferredImage from an InputStream, but then need to change them back to regular Images so they work properly within JavaFX. I have tried many variations, but this one which should seem to work best is giving me a java.lang.reflect.InvocationTargetException, so it does not even work in Eclipse properly. I know there are similar questions but none seem to answer my problem specifically (most deal with ImageIcons and JFrames) or I can't piece them together properly.
public class CardPane extends Pane
{
private static Image[] images;
private static BufferedImage img1;
private static BufferedImage img2;
private static BufferedImage img3;
private static BufferedImage img4;
private static Image image1;
private static Image image2;
private static Image image3;
private static Image image4;
static
{
try {
img1 = ImageIO.read(ResourceLoader.getImage("green-club-100.png"));
img2 = ImageIO.read(ResourceLoader.getImage("pink-heart-100.png"));
img3 = ImageIO.read(ResourceLoader.getImage("black-spade-100.png"));
img4 = ImageIO.read(ResourceLoader.getImage("blue-diamond-100.png"));
}
catch (IOException e) {
e.printStackTrace();
}
image1 = SwingFXUtils.toFXImage(img1,null);
image2 = SwingFXUtils.toFXImage(img2,null);
image3 = SwingFXUtils.toFXImage(img3,null);
image4 = SwingFXUtils.toFXImage(img4,null);
images[0] = image1;
images[1] = image2;
images[2] = image3;
images[3] = image4;
}
}
final public class ResourceLoader {
public static InputStream getImage(String path) {
InputStream input = ResourceLoader.class.getResourceAsStream(path);
if (input == null)
input = ResourceLoader.class.getResourceAsStream("/" + path);
return input;
}
}
Here is what it looks like on the file explorer. I configured the build path to have the res folder marked as the source folder, which I believe is what I am supposed to do.
Is there a quick fix to get rid of the invocation error, or am I going about this whole thing entirely wrong? Sorry if the question is confusing or seems stupid, I'm pretty new to coding and to this site. Any help would be greatly appreciated, and if any more code needs to be seen, I will be glad to share! Thanks!
Edit: I have tried to different ways with the advice in mind, but neither seem to work. They run in Eclipse fine and on my computer, but the images will not show up when the jar is opened on other devices.
Here is the first with the resource loader
private static Image[] images = new Image[4];
private static Image image1 = new Image(ResourceLoader.getImage("green-club-100.png"));
private static Image image2 = new Image(ResourceLoader.getImage("pink-heart-100.png"));
private static Image image3 = new Image(ResourceLoader.getImage("black-spade-100.png"));
private static Image image4 = new Image(ResourceLoader.getImage("blue-diamond-100.png"));
static
{
images[0] = image1;
images[1] = image2;
images[2] = image3;
images[3] = image4;
}
And the second without, using URLs as in example 2
public static URL url1 = CardGridPaneTest.class.getResource("green-club-100.png");
public static URL url2 = CardGridPaneTest.class.getResource("pink-heart-100.png");
public static URL url3 = CardGridPaneTest.class.getResource("black-spade-100.png");
public static URL url4 = CardGridPaneTest.class.getResource("blue-diamond-100.png");
public static Image image1 = new Image(url1.toString());
public static Image image2 = new Image(url2.toString());
public static Image image3 = new Image(url3.toString());
public static Image image4 = new Image(url4.toString());
public static Image[] images = new Image[4];
static {
images[0] = image1;
images[1] = image2;
images[2] = image3;
images[3] = image4;
}

The code is fine. You are getting that exception because you didn't initialize the images array. Define images as;
Image[] images = new Image[4].

Related

Java SWT - Is it correct to keep most used Images as static?

can someone tell me if in SWT (or others, like JavaFX), using images as static without disposing them is bad or acceptable. For instance:
public class TemplateImage {
/** ================== STATIC FINAL VALUES ================== */
/** Buttons */
public static final Image IMAGE_BUTTON_EXPAND = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/plus.png"));
public static final Image IMAGE_BUTTON_REDUCE = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/minus.png"));
public static final Image IMAGE_BUTTON_CREATE = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/write.png"));
public static final Image IMAGE_BUTTON_DELETE = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/delete.png"));
public static final Image IMAGE_BUTTON_MODIFY_REFERENCE = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/link.png"));
/** Miscellaneous */
/** Status */
public static final Image IMAGE_ERROR_STATUS = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/error-status.png"));
public static final Image IMAGE_WARNING_STATUS = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/warning-status.png"));
public static final Image IMAGE_UNRESOLVED_CONFLICT_STATUS = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/unresolved-conflict-status.png"));
public static final Image IMAGE_NEW_STATUS = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/new-status.png"));
public static final Image IMAGE_ANGRY_STATUS = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/status-angry.png"));
public static final Image IMAGE_DISAPPOINTED_STATUS = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/status-disappointed.png"));
public static final Image IMAGE_HAPPY_STATUS = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/status-happy.png"));
public static final Image IMAGE_NEUTRAL_STATUS = new Image(Display.getCurrent(), TemplateImage.class.getResourceAsStream("/icons/status-neutral.png"));
...
The calls to Display.getCurrent() mean that you must be sure that this static initialization is done after the Display device is created and that the initialization runs on the user interface thread. You will get an error if either of these is wrong.
Other than that there is no problem with static images.
If what's using those images is expected to be unloadable from memory or part of a long living process, like Eclipse plug-ins, then static is bad. Otherwise, it's fine.

Setting ImageView in JavaFX based on a gif animation

I am fairly new to programming and have recently encountered a problem that I have not found a solution for online. I have created an ImageView in FXML and gave it an FXid of "gif1". I am using code from this stackoverflow post but I tried modifying it so that it would fit my needs. I put the entirety of the code in a separate java file that I called "Gif.java". Typically, "Gif.java" uses an hbox and other non applicable methods to set the ImageView. I removed those because I will be using an existing FXML document so there is no need to create a new one. In my code, I call on "Gif.java" and expect a returned ImageView. However, when I set my ImageView (gif1) to the returned ImageView, it doesn't update on the screen.
Here is the link to the gif post: How I can stop an animated GIF in JavaFX?
Here is my code that I use to update gif1:
#FXML
private void setUp(){
Gif newGif = new Gif("rightrock.gif"); // Creates object newGif and passes through path to gif
gif1 = newGif.returnImage2(); // Sets gif1 to returned ImageView
}
Here is the return code in Gif.java:
public class Gif{
private Animation ani;
private ImageView test;
public Gif(String image) {
// TODO: provide gif file, ie exchange banana.gif with your file
ani = new AnimatedGif(getClass().getResource(image).toExternalForm(), 1000);
ani.setCycleCount(1);
ani.play();
Button btPause = new Button( "Pause");
btPause.setOnAction( e -> ani.pause());
Button btResume = new Button( "Resume");
btResume.setOnAction( e -> ani.play());
}
public void returnImage(ImageView x){
test = x; // Sets ImageView test to parameter x
}
public ImageView returnImage2() {
return test; // Return instance field test
}
public static void main(String[] args) {
launch(args);
}
public class AnimatedGif extends Animation {
public AnimatedGif( String filename, double durationMs) {
GifDecoder d = new GifDecoder();
d.read( filename);
Image[] sequence = new Image[ d.getFrameCount()];
for( int i=0; i < d.getFrameCount(); i++) {
WritableImage wimg = null;
BufferedImage bimg = d.getFrame(i);
sequence[i] = SwingFXUtils.toFXImage( bimg, wimg);
}
super.init( sequence, durationMs);
}
}
public class Animation extends Transition {
private ImageView imageView;
private int count;
private int lastIndex;
private Image[] sequence;
private Animation() {
}
public Animation( Image[] sequence, double durationMs) {
init( sequence, durationMs);
}
private void init( Image[] sequence, double durationMs) {
this.imageView = new ImageView(sequence[0]);
this.sequence = sequence;
this.count = sequence.length;
setCycleCount(1);
setCycleDuration(Duration.millis(durationMs));
setInterpolator(Interpolator.LINEAR);
}
protected void interpolate(double k) {
final int index = Math.min((int) Math.floor(k * count), count - 1);
if (index != lastIndex) {
imageView.setImage(sequence[index]);
lastIndex = index;
}
}
public ImageView getView() {
returnImage(imageView); // This runs returnImage with the ImageView that I want to set
return imageView;
}
}
Any help would be greatly appreciated!

NullPointerException while getting an Image

I am having trouble setting images in my newest game. When I call the method getImage(String), and I get the Image like so:
Image head = getImage("Torso_model_01.png");
I get the following error message:
Err: java.lang.NullPointerException
At PB2Main.Body(Body.java : 27)
...
and so on...
On this tutorial, it explains how to get an image using ImageIcon like so:
String imgFile = "Images/" + img;
URL imgURL = getClass().getClassLoader().getResource(imgFile);
ImageIcon imageIcon;
Image image;
if(imgURL != null){
imageIcon = new imageIcon(imgURL);
image = imageIcon.getImage();
}
final Image anImage = image;
I made a method for this:
public URL getURL(String img){
String imgFile = "Images/" + img;
URL imgURL = getClass().getClassLoader().getResource(imgFile);
return imgURL;
}
Then I made a method called getImage(String)
public Image getImage(String img) {
ImageIcon imageIcon;
Image image;
URL imgURL = getClass().getClassLoader().getResource(getURL(img));
if(imgURL != null){
imageIcon = new ImageIcon(imgURL);
image = imageIcon.getImage();
return image;
}
System.err.println("Unable to Locate Image: " + imgURL);
}
Now, I have a class called Body.
In that class, I have a constructor:
public Body(float x, float y, String head, String torso){//atm this is just so i can get the image to actually draw on the screen
Image Head = debugger.getImage(head);// debugger doubles as a library and debugger
//i also can't have this class extend debugger otherwise it will create a window :/
// is that a glitch or something in Java? :L perhaps i just don't understand
// inheritance very well and what happens exactly when you inherit a class :(
Image Torso = debugger.getImage(torso);
g2.drawImage(Head, canvas.geWidth()/ 2,canvas.getHeight()/2, null)// canvas: the window to
//draw to
// can someone also quickly explain in their answer what an image observer is please?
g2.drawImage(Torso, Head.getX() - 5, Head.getY() - 5, null);
}
The compiler gives me the following error message:
java.lang.NullPointerException
At PlazmaBurst2.Body(Body.java: 37)
//the code it brings me to is line 1 in the constructor:
/* null: */ Image Head = debugger.getImage(img);
I don't understand where this NullPointerException is coming from. I did it exactly how they do it in the Custom Graphics Programming section of the same site.
The code works fine if I just copy and paste the code, but not if I use the method getImage(String).
You're problem is on line 3 of getImage(String):
URL imgURL = getClass().getClassLoader().getResource(getURL(img));
This should be changed to:
URL imgURL = getURL(img);

I want to simplify things in my Java program

I made a game using NetBeans design tool, called WordHunt. It looks like this:
I need to make a class that will apply a mouseover effect to those 16 labels I have. This is the code that changes the icon B when enter the mouse:
private void b1MouseEntered(java.awt.event.MouseEvent evt) {
b1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/ip/imag/" +B+ ".png")));
}
I had applied a default icon to the label.
After making that class, instead of writing:
b1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/ip/imag/" +B+ ".png")));
to write className(b1 ,B);
For the next label, the same thing
className(b2 ,C);
Observation: b1 is a label and I have all letters icon in .png format from A to Z.
Can anybody give me an idea of how I can do that?
If I understand what you want to do, you can use this method:
public void setRolloverIcon(Icon rolloverIcon)
defined in the class JButton to configure the rollover icon.
Just create a simple class like this:
class HoverEffectButton extends JButton{
HoverEffectButton(Image img1, Image img2) {
super(new ImageIcon(img1));
this.setRolloverIcon(new ImageIcon(img2));
}
}
Hope this will help.
And of course you can create a helper class that permits to load an image according to the image name
class AssetsHelper{
private static final String DEFAULT_ASSETS_ROOT = "assets/";
private static final String DEFAULT_IMAGE_SUBFIX = ".png";
public static Image loadImage(String name){
BufferedImage img = null;
try {
img = ImageIO.read(new File(DEFAULT_ASSETS_ROOT + name + DEFAULT_IMAGE_SUBFIX));
} catch (IOException e) {
....
}
return img;
}
}
How about something like this: (rough draft)
// for storage so we don't load it for each mouse-over
HashMap<String, ImageIcon> images = new HashMap<String, ImageIcon>();
void setIcon(JLabel button, String image)
{
if (images.containsKey(image))
return images.get(image);
else
{
String path = "/ip/imag/" + image + ".png";
ImageIcon icon = new ImageIcon(getClass().getResource(path));
images.put(image, icon);
return icon;
}
}
And then:
setIcon(b1, "B");
But you should probably consider using buttons so you can use setRolloverIcon rather than MouseEntered.
public class MyButton extends JButton {
private ImageIcon normalIcon;
private ImageIcon hoverIcon;
public MyButton(String normalURL) {
String hoverURL = normalURL.replaceFirst("\\.png$", "-hover.png");
normalIcon = new ImageIcon(getClass().getResource("/ip/imag/" +B+ ".png"); // or so
hoverICon = ...
}
private void b1MouseEntered(MouseEvent evt) {
setIcon(hoverIcon);
}
}
Firstly at the top of your code add this import:
import javax.swing.ImageIcon;
//Then you only need to write
new ImageIcon(...);
Instead of:
new javax.swing.ImageIcon(...)
Already shorter :)
Then you can create a hashmap of the images preloaded where each instance of B is the key and the loaded icon is the value.
if i get u well i think you want just an image and not evry image to chang when mouse is on it right. if that is the case what u should do is to get the position of each image in a buffer and compare it with the mouse x n y position to know wc image to change. I hope this solve your problem

stitch images together in java

I'm trying to stitch some images together using java. I have a bunch of images I'd like to stitch together and they are all the same dimensions so it's really just a question of lining them up next to each other I suppose. I have it working but it's very slow and probably very memory intensive. I'm wondering if there's an easier way:
public static void main(String[] args) throws IOException
{
int dim = 256;
BufferedImage merged = null;
for(int y = 0; y<10;y++)
{
for(int x = 0; x<10;x++)
{
URL url = new URL(someURL);
BufferedImage nextImage = ImageIO.read(url);
if(merged==null)
merged=nextImage;
else
{
BufferedImage tempMerged;
tempMerged = new BufferedImage(10*dim,10*dim,merged.getType());
//Write first image
for(int xx=0;xx<merged.getWidth();xx++)
for(int yy=0;yy<merged.getHeight();yy++)
tempMerged.setRGB(xx,yy,merged.getRGB(xx,yy));
//Write img2
for(int xx=0;xx<dim;xx++)
{
for(int yy=0;yy<dim;yy++)
{
int destX = (x*dim)+xx;
int destY = (y*dim)+yy;
tempMerged.setRGB(destX,destY,nextImage.getRGB(xx,yy));
}
}
merged=tempMerged;
}
System.out.println("Stitched image at "+x+","+y);
}
}
ImageIO.write(merged, "png", new File("merged.png"));
}
#Thomas: You'd have to create a new image of twice the size of the source images (e.g. for 2x 512x512 the new image should be 512x1024 or 1024x512). Then you'd render the source images to the respective area/rectangle of the target image
E.G. TiledImageWrite.java
import java.awt.image.BufferedImage;
import java.awt.*;
import javax.swing.*;
import java.net.URL;
import java.io.File;
import javax.imageio.ImageIO;
class TiledImageWrite {
public static void main(String[] args) throws Exception {
URL dayStromloUrl = new URL("https://i.stack.imgur.com/OVOg3.jpg");
URL nightStromloUrl = new URL("https://i.stack.imgur.com/lxthA.jpg");
final BufferedImage dayStromloImage = ImageIO.read(dayStromloUrl);
final BufferedImage nightStromloImage = ImageIO.read(nightStromloUrl);
final int width = dayStromloImage.getWidth();
final int height = dayStromloImage.getHeight();;
final BufferedImage columnImage =
new BufferedImage(width,2*height,BufferedImage.TYPE_INT_RGB);
final BufferedImage rowImage =
new BufferedImage(2*width,height,BufferedImage.TYPE_INT_RGB);
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JPanel gui = new JPanel(new BorderLayout(3,3));
Graphics2D g2dColumn = columnImage.createGraphics();
g2dColumn.drawImage(dayStromloImage,0,0, null);
// start this one at 'height' down the final image
g2dColumn.drawImage(nightStromloImage,0,height, null);
Graphics2D g2dRow = rowImage.createGraphics();
g2dRow.drawImage(dayStromloImage,0,0, null);
// start this one at 'width' across the final image
g2dRow.drawImage(nightStromloImage,width,0, null);
gui.add(new JLabel(new ImageIcon(columnImage)),BorderLayout.CENTER);
gui.add(new JLabel(new ImageIcon(rowImage)),BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null, gui);
}
} );
ImageIO.write(columnImage, "png", new File("column.png"));
ImageIO.write(rowImage, "png", new File("row.png"));
}
}
column.png
AFAIK what you're doing here is to write layers to a image. However, the png format doesn't support this.
You'd have to create a new image of twice the size of the source images (e.g. for 2x 512x512 the new image should be 512x1024 or 1024x512). Then you'd render the source images to the respective area/rectangle of the target image.
I figured out why it was going slow. In reality, I didn't want to merge images together, but rather stitch together a bunch of images. What I was doing was rewriting the original image everything when all I really want to do is add to it. Much faster now!

Categories

Resources