Images in Java (part 2)

Outline

Complete code to load images

Just call one of these methods when you need to load an image.

1. Using ImageIO.read() to get a BufferedImage

/*
   Use ImageIO.read() and get a BufferedImage back
   It requires try-catch.
   A non-existent image is set to null.
*/
static BufferedImage loadImage(String filename) {
	BufferedImage img = null;			
	try {
		img = ImageIO.read(new File(filename));
	} catch (IOException e) {
		System.out.println(e.toString());
		JOptionPane.showMessageDialog(null, "An image failed to load: " + filename , "ERROR", JOptionPane.ERROR_MESSAGE);
	}
	//DEBUG
	//if (img == null) System.out.println("null");
	//else System.out.printf("w=%d, h=%d%n",img.getWidth(),img.getHeight());
	
	return img;
}

2. Using Toolkit to get an Image

/*
   Use Toolkit.getImage() and get a sun.awt.image.ToolkitImage object
   If it doesn't load, it creates an Image that is size -1,-1, so we'll then set it to be null.
 */
static Image loadImage(String filename) {
	Image img = Toolkit.getDefaultToolkit().getImage(filename);
	
	img.getWidth(null); //the image often doesn't show up unless you actually access it to do something first!
	// See: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4298019 (It's intentional)
	
	//System.out.printf("w=%d, h=%d%n",img.getWidth(null),img.getHeight(null)); //DEBUG

	if (img.getWidth(null) == -1) {
		img = null;
		JOptionPane.showMessageDialog(null, "An image failed to load: " + filename , "ERROR", JOptionPane.ERROR_MESSAGE);
	}	
	return img;
}

3. Using ImageIcon to get an Image This is a very simple method :)

/*
   Use ImageIcon and get a sun.awt.image.ToolkitImage object
   If it doesn't load, it creates an Image that is size -1,-1, so we'll then set it to be null.
 */
static Image loadImage(String filename) {
	ImageIcon icon = new ImageIcon(filename);
	Image img = icon.getImage();
	if (img.getWidth(null) == -1) {
		img = null;
		JOptionPane.showMessageDialog(null, "An image failed to load: " + filename , "ERROR", JOptionPane.ERROR_MESSAGE);
	}	
	return img;
}

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.

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.

drawImage() will draw an Image object or a BufferedImage object.

//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);
Update: I no longer seem to get errors if I try to draw null images.

Example:

Rectangle 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

Saving an Image to a file

Use this method to save an image to a file.

/** 
 * @param filename: String. Name of file to write to (including path if needed)
 * @param type:	"gif", "png", "jpg", "bmp", "webmp"
 * @param bufferedImage: the image that you are saving.
 */
public static void writeImageToFile (String filename, String type, BufferedImage bufferedImage) {
	File outFile = new File(filename);		
	try {
		ImageIO.write(bufferedImage, type, outFile);
	} catch (IOException e) {
		JOptionPane.showMessageDialog(null, "Unable to save image " + filename , "ERROR", JOptionPane.ERROR_MESSAGE);
		e.printStackTrace();
	} 
}

The file object does not need closing

Resizing / scaling an image

Here we're not just drawing an image at a different resolution, we're actually scaling/resizing it to make a new image of the new size.
I've only tried shrinking images so far.

Code

We read in a file as an Image (or BufferedImage), then we do the actual scaling

BufferedImage img = loadImage(filename);

//scale the image to be 100x80. This does not output BufferedImage, only Image
Image scaledImage = img.getScaledInstance(100, 80, Image.SCALE_DEFAULT);

//convert to an ImageIcon (optional, to put on a JButton)
ImageIcon icon =  new ImageIcon(scaledImage);
panel.add(new JButton(icon));