Images in Java

This page describes most of the things that you can do loading images into Java. It also assumes that you are using Eclipse. Eclipse has some strange behaviour when it comes to locating resource files (such as images). We'll deal with that later.

Our goals in this lesson are to

  1. to load images
  2. to display parts of an image and/or rescale an image
  3. to save the whole java package as an executable JAR file with the images included.

ImageObservers

Images can be loaded with an ImageObserver. This is some object that does something when the whole image is loaded -- useful for images thate take a long time to load, for example large images or an image that is being downloaded from the internet. We don't use this often so just put "null" for the image observer when asked.

There is a MediaTracker class that allows you to wait until all images are loaded. It's probably more useful than imageobserver, but you'll have to read up on these yourself.

1. The ImageIcon class

ImageIcons are used for situations where you want to put an icon (a small image) onto something like a JButton or a JLabel.
They display the whole image and do not allow resizing to fit the destination. Thus you have to find an image (icon) that is the exact size that you want displayed.

Sample code
ImageIcon icon = new ImageIcon("images/myimage.jpg"); JButton btn = new JButton(icon);

Note that we are just specifying the filename where the image is.
Also, always use / for path separators, not \. ie. ""c:/cat.gif" not "c:\cat.gif" (you have to escape the \ for it to work: "c:\\cat.gif")
The ImageIcon constructor can get the image from a string (filename), a URL, as well as an Image.
We'll look at where to actually put the images file later on

Scaling an ImageIcon

What if you want to scale a large image down so that it fits onto a JButton?

Sample code
Here we load an image onto the a card (actually a JButton). To do this we have to make an image and then change it to an imageicon

int cardW = 200;
int cardH = 160;
Image img = null;
//load the image
try {
	img = ImageIO.read(new File("kittens.jpg"));
} catch (IOException e) {
	System.out.println(e.toString());
	System.exit(0);
}
//scale the image
Image scaledImage = img.getScaledInstance(cardW, cardH, Image.SCALE_DEFAULT);
//convert to an ImageIcon
ImageIcon icon =  new ImageIcon(scaledImage);
JButton card1 = new JButton(icon); //the JButton is now 200x160

NOTE: (1) we loaded the image in a new way
2. We created the ImageIcon using an image in the contrstuctor

2. The Image Class

The image class. Image is an abstract class, so you can never use "new Image()". Instead use new BufferedImage().
However you can use Image img = ...something else that makes an image...

Sample code
Get an image icon and change it to an image
ImageIcon icon = new ImageIcon("myimage.jpg"); Image img = icon.getImage();

For more on using Image, see BufferedImage below

3. The BufferedImage class

BufferedImage vs Image

There's not a whole lot of difference between the two except that bufferedimages will not flicker in animated programs.

"BufferedImage, in fact, is a subclass of Image. BufferedImage gives you all sorts of control over the actual data that makes up the image and provides many capabilities beyond the basic Image class. Because it's a subclass of Image, you can still pass a BufferedImage to any of Graphics2D's methods that accept an Image. Why aren't all Images BufferedImages? Because BufferedImages are memory intensive."
-- from https://www.safaribooksonline.com/library/view/learning-java-4th/9781449372477/ch21s01.html

I don't know that BufferedImages really use significantly more resources than Images. They do allow you to manipulate the individual pixels of an image (which you can't do with the Image class).

Drawing images onto a JPanel

The Graphics.drawImage() method has a lot of different possible parameters. It's good to look over them all.
All of them have "ImageObserver" as the last parameter. We'll just put null here.

//drawing onto graphics in paintComponent(Graphics g)
  1. g.drawImage(image, 0, 0, null); //This just places the image at (0,0) on the screen. It offers no control over how large the image is.
  2. g.drawImage(image, 0, 0, getWidth(), getHeight(), null); //This stretches the image to fill the screen
  3. g.drawImage(playerImg, player.x, player.y, player.width, player.height, null); //draw the player image into the player rectangle (image is scaled to fit)
  4. g.drawImage(image, 0, 0, 100, 100, null); //scales the image to fill a 100x100 square located at (0,0).
  5. g.drawImage(image, dx, dy, dw, dh, sx, sy, sw, sh, null);

This last form lets you specify the destination rectangle, as all of the previous examples do, but also lets you specify the source rectangle, which means that you can just select one part of an image to draw. This is especially useful for spritesheets.

In all of these examples you should always check to see if the image is null before drawing it or you'll get an error:
if (image != null) g.drawImage(image, 0, 0, 100, 100, null);

asteroid = new Rectangle (200,200, 64, 64); // starting location and 64x64 pixels size of asteroid image g.drawImage(imgAsteroid, //the image file asteroid.x, asteroid.y, asteroid.x + asteroid.width, asteroid.y + asteroid.height, //destination 0,0, asteroid.width, asteroid.height, //source null); //imageObserver

4. The ImageIO class

This is mostly used for loading (and saving) images.

There are a whole bunch of ways to load an image:

"It is easy to load an image with the static read() methods of the ImageIO class, which accept either a File, URL, or InputStream. Images loaded by the ImageIO.read() methods are fully loaded before they are returned, so the method blocks until they are done." -- from Safari Books

Saving an image

This will probably be a BufferedImage because you can modify them.

File outFile = new File("/tmp/myImage.png");
ImageIO.write( buffimg , "png", outFile ); //The second argument is a string identifier that names the image type.

Method to load images

/* This method loads an image from a filename (which includes the relative path).
 * It returns the BufferedImage or a null if the image doesn't load. */
static BufferedImage loadImage(String fileName) {
	BufferedImage img = null;
	try {		
		img = ImageIO.read(new File(fileName));
	} catch (IOException e) {			
		e.printStackTrace();
		JOptionPane.showMessageDialog(null, "An image failed to load: " + fileName , "ERROR", JOptionPane.ERROR_MESSAGE);
	}
	return img;
}

Location of image files in Eclipse Workspace

I'll be posting complete working programs Monday evening, illustrating all of the things mentioned above along with a video showing how to make an executable Jar with resources.

JAR files

JAR files are read-only. You can't write data files to them in your program.