1.124 Lecture 16 | 11/2/2000 |
Images provide a way to augment the aethetic appeal of a Java program. Java provides support for two common image formats: GIF and JPEG. An image that is in one of these formats can be loaded by using either a URL or a filename.
The basic class for representing an image is java.awt.Image.
Packages that are relevant to image handling are java.applet, java.awt
and java.awt.image.
// In a method in an Applet subclass, such as
the init() method:
Image image1 = getImage(getCodeBase(), "imageFile.gif");
Image image2 = getImage(getDocumentBase(), "anImageFile.jpeg");
Image image3 = getImage(new URL("http://java.sun.com/graphics/people.gif"));
In the first example, the code base is the URL of the directory that contains the applets .class file. In the second example, the document base is the URL of the directory containing the HTML document that loads the applet.
Alternatively, we may use the getImage() methods provided by the Toolkit class.
Toolkit toolkit = Toolkit.getDefaultToolkit();
Image image1 = toolkit.getImage("imageFile.gif");
Image image2 = toolkit.getImage(new URL("http://java.sun.com/graphics/people.gif"));
In general, applets cannot read files that are on the local machine for reasons of security. Thus, applets typically download any images they need from the server.
Note that getImage() returns immediately without waiting for
the image to load. The image loading process occurs lazily, in that
the image doesn't start to load until the first time we try to display
it.
This version draws an image at the specified position using its natural size:
boolean drawImage(Image img, int x, int y, ImageObserver observer)
This version draws an image at the specified position, and scales it to the specified width and height:
boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)
The ImageObserver is a mechanism for tracking the loading of an image (see below). One of the uses for an ImageObserver is to ensure that the image is properly displayed once it has finished loading. The return value from drawImage() is rarely used: this value is true if the image has been completely loaded and thus completely painted, and false otherwise.
Here is a simple example of loading and displaying images.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// This applet displays a single image twice,
// once at its normal size and once much wider.
public class ImageDisplayer extends JApplet {
static String imageFile = "images/rocketship.gif";
public void init() {
Image image = getImage(getCodeBase(),
imageFile);
ImagePanel imagePanel
= new ImagePanel(image);
getContentPane().add(imagePanel,
BorderLayout.CENTER);
}
}
class ImagePanel extends JPanel {
Image image;
public ImagePanel(Image image) {
this.image = image;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Paint background
// Draw image at its natural
size first.
g.drawImage(image, 0,
0, this); //85x62 image
// Now draw the image
scaled.
g.drawImage(image, 90,
0, 300, 62, this);
}
}
The MediaTracker class provides a relatively simple way to delay drawing until the image loading process is complete. We can modify the ImageDisplayer applet to perform the following steps:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// This applet displays a single image twice,
// once at its normal size and once much wider.
public class ImageDisplayer extends JApplet {
static String imageFile = "images/rocketship.gif";
public void init() {
Image image = getImage(getCodeBase(),
imageFile);
// Create a media tracker
and add the image to it. If we had several
// images to load,
they could all be added to the same media tracker.
MediaTracker tracker
= new MediaTracker(this);
tracker.addImage(image,
0);
// Start downloading
the image and wait until it finishes loading.
try {
tracker.waitForAll();
}
catch(InterruptedException
e) {}
ImagePanel imagePanel
= new ImagePanel(image, tracker);
getContentPane().add(imagePanel,
BorderLayout.CENTER);
}
}
class ImagePanel extends JPanel {
Image image;
MediaTracker tracker;
public ImagePanel(Image image, MediaTracker tracker)
{
this.image = image;
this.tracker = tracker;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Paint background
// Check that the image
has loaded before trying to draw it.
if (!tracker.checkAll())
{
g.drawString("Please wait...", 0, 0);
return;
}
// Draw image at its natural
size first.
g.drawImage(image, 0,
0, this); //85x62 image
// Now draw the image
scaled.
g.drawImage(image, 90,
0, 300, 62, this);
}
}
imageUpdate(Image img, int flags, int x, int y, int width, int height)
which will be called whenever an interesting milestone in the image loading process is reached. The flags argument can be examined to determine exactly what this milestone is. The ImageObserver interface defines the following constants, against which the flags argument can be tested using the bitwise AND operator:
public static final int WIDTH;
public static final int HEIGHT;
public static final int PROPERTIES;
public static final int SOMEBITS;
public static final int FRAMEBITS;
public static final int ALLBITS;
public static final int ERROR;
public static final int ABORT;
The java.awt.Component class implements the ImageObserver
interface and provides a default version of imageUpdate(), which
calls repaint() when the image has finished loading. The following
example shows how we could modify the ImageDisplayer applet, so
that the ImagePanel class provides its own version of imageUpdate()
instead of using the one that it inherits from java.awt.Component.
Note that we pass this as the last argument to drawImage().
import java.awt.*;
import java.awt.event.*;
import java.awt.image.ImageObserver;
import javax.swing.*;
// This applet displays a single image twice,
// once at its normal size and once much wider.
public class ImageDisplayer extends JApplet {
static String imageFile = "images/rocketship.gif";
public void init() {
Image image = getImage(getCodeBase(),
imageFile);
ImagePanel imagePanel
= new ImagePanel(image);
getContentPane().add(imagePanel,
BorderLayout.CENTER);
}
}
class ImagePanel extends JPanel implements ImageObserver {
Image image;
public ImagePanel(Image image) {
this.image = image;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Paint background
// Draw image at its natural
size first.
g.drawImage(image, 0,
0, this); //85x62 image
// Now draw the image
scaled.
g.drawImage(image, 90,
0, 300, 62, this);
}
public boolean imageUpdate(Image image, int
flags, int x, int y,
int width,
int height) {
// If the image has
finished loading, repaint the window.
if ((flags & ALLBITS)
!= 0) {
repaint();
return false; // Return false to say we don't need further notification.
}
return true;
// Image has not finished loading, need further notification.
}
}
http://java.sun.com/docs/books/tutorial/uiswing/painting/movingImage.html
Note that this example makes use of a Timer class to control the delay between animation frames, instead of the Thread.sleep() method that we used in the bouncing ball example. The Timer class is used to trigger an ActionListener event handler at regular intervals. This event handler is used to update the position of the image (via the frame number) and then issue a repaint() request. A more detailed discussion of the use of the Timer class can be found at
http://java.sun.com/docs/books/tutorial/uiswing/painting/animLoop.html
http://java.sun.com/docs/books/tutorial/uiswing/painting/imageSequence.html
The portion of code that is of main interest is:
// In initialization code.
Image[] images = new Image[10];
for (int i = 1; i <= 10; i++) {
images[i-1] = getImage(getCodeBase(),
"images/duke/T"+i+".gif");
}
// In the paintComponent method.
g.drawImage(images[ImageSequenceTimer.frameNumber
% 10], 0, 0, this);
This is a good example of why a MediaTracker should be used to delay drawing until after all the images have loaded. The following modified example does this.
http://java.sun.com/docs/books/tutorial/uiswing/painting/example-swing/MTImageSequenceTimer.java