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.

Outline

ImageObservers

Images can be loaded with an ImageObserver. This is some object that does something when the whole image is loaded -- useful for images that 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.

Different Types of Image Objects

There are three different objects that can store images. This makes things a bit complicated.

We'll also look at how to create each of these images by loading a picture from a file.

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 or else the JButton increases in size to fit the image.

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

ImageIcons are also useful for reading in a picture and then converting it to some other format

Creating ...

ImageIcons can be created from a text string (for file name) or a URL or an Image.
ImageIcon icon = new ImageIcon(String); ImageIcon icon = new ImageIcon(URL); ImageIcon icon = new ImageIcon(Image);

Please see the separate document on image icons for more information

2. The Image Class

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

Abstract Classes and Polymorphism in more detail

The Image class is extended by two classes: BufferedImage and VolatileImage as well as by something called "sun.awt.image.ToolkitImage".
This means that any Image object is actually one of these three objects. (We're never using VolatileImage.)

Anything that uses an Image, can use any of the subclasses that extend Image.
For example: g.drawImage(bgImage, 0, 0); will work with a BufferedImage, or a VolatileImage, or a sun...ToolkitImage.
This is why a lot of methods just specify that the image is an Image class object. (There are some that specify that it has to be a BufferedImage.)

Creating ...

Images are actually created as one of the subclasses and then stored in an Image reference variable. We'll see how this works when we look at converting from one image type to another.

Image image = new ImageIcon("myImage.png").getImage();
OR
Image image = Toolkit.getDefaultToolkit().getImage("myImage.png");
NOTE: Both of these methods make a sun.awt.image.ToolkitImage object
This toolkit method can use a String or a URL to get the image.

3. The BufferedImage class

We will be using BufferedImage as our main java image format as opposed to Image or ImageIcon, though these do have their uses.

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).

Here's what Java documentation says:

The BufferedImage class is a cornerstone of the Java 2D immediate-mode imaging API. It manages the image in memory and provides methods for storing, interpreting, and obtaining pixel data. Since BufferedImage is a subclass of Image it can be rendered by the Graphics and Graphics2D methods that accept an Image parameter. A BufferedImage is essentially an Image with an accessible data buffer. It is therefore more efficient to work directly with BufferedImage. A BufferedImage has a ColorModel and a Raster of image data. The ColorModel provides a color interpretation of the image's pixel data. The Raster performs the following functions:

Creating ...

BufferedImage bim = ImageIO.read(new File(fn));
ImageIo.read() is a bit unusual in that it will work with a File object or InputStream or URL.
If you have a String filename, then just say "new File(filename)".

Converting from one form to another

Variable names for these examples:
img is an Image
icon is an ImageIcon
bim is a BufferedImage

ImageIcon to Image and vice versa

Image img = icon.getImage();

ImageIcon icon = new ImageIcon(image);

Image to BufferedImage and vice versa

Image img = bim;

Casting: BufferedImage bim = (BufferedImage) img; //ONLY if img is already a BI.

Since a number of methods return the sun.awt.image.ToolkitImage, we will need to use this method below. It works for ANY image

BufferedImage bim = new BufferedImage( img.getWidth(null), img.getHeight(null),  BufferedImage.TYPE_INT_ARGB);
bim.getGraphics().drawImage(img, 0, 0, null);
//bim now contains the same image that was in "img"

ImageIcon to BufferedImage and vice versa

Since BufferedImage extends Image we can do this: ImageIcon icon = new ImageIcon(bim); // if it works with an Image, it will work with a BufferedImage.

Casting: BufferedImage bim = (BufferedImage) icon.getImage(); NO, it’s a sun.awt.image.ToolkitImage !!!

BufferedImage bim = new BufferedImage( icon.getWidth(), icon.getHeight(),  BufferedImage.TYPE_INT_ARGB);
Graphics g = bim.createGraphics();
icon.paintIcon(null, g, 0,0); // paint the Icon to the BufferedImage.
g.dispose();