Having learned how to draw shapes using the graphics primitives in chapter 14, you are ready now to go a step further! This chapter explains how to use graphic pictures inside your Visual J++ programs. In addition, you'll learn what it's like to work with those images when you want to test their load time across the Internet or crop the images to make them smaller.
This material in this chapter can get rather advanced in a hurry. Despite the fact that you are new to graphics, however, you'll be able to understand the basics of this chapter's graphics work because the Java.awt class package includes pre-defined routines that help lighten your programming burden.
Often you'll want to display a digital photograph or another kind of graphic file from within your Visual J++ program. Your applet can display graphic images using the drawImage() method. drawImage() is misleading because you do not draw anything in the same sense that you drew with chapter 14's graphics drawing methods. The drawImage() method displays pictures from .Gif file images that you've gathered from other sources.
Displaying images doesn't take a lot of effort but you must place several statements throughout your applet to display a graphic image. When you want to display a file's graphic image, perform these general steps:
An Image object is just a special object that can hold an image loaded from a disk file. Here is the general format of the Image object's constructor that you'll perform:
Image imageName;
The following statement instantiates a new image called myPicture:
Image myPicture; // Instantiates an image object
You should instantiate your Image object somewhere towards the top of your applet, preferably right before your applet's class definition and outside of any method. The Image object is then available to any method that follows due to the scoping rules for such object instantiation locations. Here are the first few lines in a Visual J++ applet that defines an Image object:
//*************************************************************************
// myGraphic.java: Applet
//
//*************************************************************************
import java.applet.*;
import java.awt.*;
//=========================================================================
// Main Class for applet myGraphic
//=========================================================================
public class myGraphic extends Applet
{
Image myPicture; // Instantiates an Image object
You should recognize by now that this code follows the same format as that created by Visual J++'s New Project Wizard.
Once you instantiate the Image object, you must load the image from your disk into the Image object (you can also supply an URL location to load an image from the Internet). The getImage() method loads the image into the Image object. Here is the format for the drawImage() method:
imageObject = getImage(URL, String imageFile);
The first parameter tells your applet where to grab the image, either from a URL that you specify or from the current applet's HTML location. Often, you'll see getDocumentBase() for the first parameter because getDocumentBase() sends the current HTML page location from your disk drive to the getImage() method, letting you load a .Gif image from your applet's hard drive location. The second parameter holds the name of the image you want to load. You can specify a drive and path, but be sure that you use an escape sequence character to represent the path's backslashes if you use a backslash inside the string. (Of course, you can use a string variable with the file name as well.)
In one sense, the Image object that receives the image does not really hold the image but points to it. The image loads when your subsequent drawImage() method requests the image.
drawImage() can appear in the following formats:
boolean drawImage(Image image, int x, int y, ImageObserver ImObs);
boolean drawImage(Image image, int x, int y, int width,
[ic:ccc]int height, ImageObserver ImObs);
boolean drawImage(Image image, int x, int y, Color bckColor,
[ic:ccc]ImageObserver ImObs);
boolean drawImage(Image image, int x, int y, int width, int height,
[ic:ccc]Color bckColor, ImageObserver ImObs);
Table 15.1 describes each of drawImage()'s parameters.
Table 15.1 The drawImage() Parameters Determines How Your Graphic File Image Appears
Parameter | Description |
bckColor | The background color on which you want to place the image if the color is to differ from the current background color. |
height | The height, in pixels, of the displayed image (if the image does not fit, your applet scales the image to fit your width and height request). |
image | Your instantiated Image object name. |
imObs | The ImageObserver object (see the next section, "Use MediaTracker to Manage the Timing"). |
width | The width, in pixels, of the displayed image (if the image does not fit, your applet scales the image to fit your width and height request). |
x | The x-coordinate location for the image's placement. |
y | The y-coordinate location for the image's placement. |
Place the drawImage() method inside the paint() method so the image draws whenever your applet's window is redrawn.
Listing 15.1 shows a sample source code that draws the image on the applet shown in figure 15.1. I took listing 15.1 from a file generated with the New Project Wizard but I removed a lot of the extra comments and methods that are not needed here.
An applet can display a .Gif image file.
Listing 15.1 Displaying a .Gif Image from an Applet
//*************************************************************************
// grImge.java: Applet
//*************************************************************************
import java.applet.*;
import java.awt.*;
//========================================================================
// Main Class for applet grImge
//
//========================================================================
public class grImge extends Applet
{
Image myPicture; // Instantiate an Image object
// grImge Class Constructor
//-------------------------------------------------------------------
public void init()
{
resize(400, 300);
// Associate the Image object to the .GIF located in
// the same location as the HTML file.
myPicture = getImage(getDocumentBase(), "animals.gif");
}
//-------------------------------------------------------------------
// grImge Paint Handler
//-------------------------------------------------------------------
public void paint(Graphics g)
{
// Load and displays the image
g.drawImage(myPicture, 0, 0, this);
}
public void start()
{
}
public void stop()
{
}
}
The imageObserver object introduced in the previous section works with a helper class that informs you when an image object completely loads. The load time is critical not because the image takes a moment to load from your disk to your Web browser or the JView applet viewer that you use for testing, but rather a loading delay often occurs when an end-user views your Web page. The image must transfer from its source on your hard disk or from another URL to your end-user's Web site. Graphic images can get large and download slowly.
The Java language developers took advantage of Java's OOP-like nature and supplied a helper class called MediaTracker to watch image loads and inform your applet when the image completely appears on your end-user's system. As with all objects, if you want to create a media tracking object to monitor an image's loading, instantiate the MediaTracker object using this format:
MediaTracker mTrackerName = new MediaTracker(this);
[ic:ccc]// Instantiates the object
The only parameter you need to supply is the mTrackerName parameter, which will be your MediaTracker's object name. The following statement, therefore, instantiates a media tracking object named medTracker:
MediaTracker medTracker = new MediaTracker(this);
[ic:ccc]// Instantiates the object
Once you retrieve your image with getImage(), you must tell your media tracking object to keep track of the image's loading progress. The media tracking object keeps track of the image or images you tell it to track only, not necessarily all images in the applet. If you want to track the loading of multiple images, you can instantiate multiple MediaTrackers or assign the multiple images to a single MediaTracker.
The way that a media tracking object keeps track of an image's loading is by an identifying number that you assign to the image when you add the image to the MediaTracker. Suppose you just used getImage() to load a graphic image from your disk into an Image object named myPicture. You can tell the medTracker MediaTracker to monitor the image's loading with the following statement:
medTracker.addImage(myPicture, 0); // Assign the image
[ic:ccc]load to the tracker
The second parameter indicates the tracker ID number. The ID can range from 0 to 255. You can assign multiple images to the MediaTracker and give them all the same ID as done here:
medTracker.addImage(myPicture, 0); // Assign the image
[ic:ccc]load to the tracker
medTracker.addImage(anotherPic, 0); // Assign the image load
[ic:ccc]to the tracker
medTracker.addImage(thirdPic, 0); // Assign the image load
[ic:ccc]to the tracker
The MediaTracker now knows to track all three images. If, instead, you assigned the three graphic images unique IDs, you could track them separately. The following statements assign the MediaTracker's unique ID numbers:
medTracker.addImage(myPicture, 0); // Assign the image load
[ic:ccc]to the tracker
medTracker.addImage(anotherPic, 1); // Assign the image load
[ic:ccc]to the tracker
medTracker.addImage(thirdPic, 2); // Assign the image load
[ic:ccc]to the tracker
Use the waitForID() method to wait for the image load. The waitForID() method suspends your applet's execution until the image ID passed to waitForID() completely loads. The following statement makes the MediaTracker suspend the applet's execution until the image completely loads:
medTracker.waitForID(1); // Wait for the image with the
[ic:ccc]tracker id of 1
If you do not want your applet to continue executing until all images load, use waitForAll() like this:
medTracker.waitForAll(); // Wait for every image
Of course, this waitForAll() method waits only for the images assigned to the tracker named medTracker.
Use the statusID() tracker method to initiate a load but not wait for the load. The following statement tells the tracker to load the image or images assigned to its ID of 0 (the true parameter indicates that you want the loading to begin with this statement):
medTracker.statusID(0, true); // Loads all 0 images
Instead of loading the applet's images assigned to the one ID, you can load all the images by using statusAll() like this:
medTracker.statusAll(true); // Loads all images
In addition to triggering the loading, you can check the loading status with checkID() and checkAll(). Here is the format of these methods:
boolean checkID(int id); // Checks to see if the
[ic:ccc]tracked image is loaded
boolean checkAll(); // Checks all tracked images
Suppose that you instantiate a MediaTracker object and an Image object at the top of your applet like this:
MediaTracker medTracker; // Instantiates a MediaTracker object
Image myPicture; // Instantiates an Image object
Inside init(), you can connect the disk image to the Image object and initialize the MediaTracker as follows:
myPicture = getImage(getDocumentBase(), "animals.gif");
medTracker = new mediaTracker(this); // Assigns applet to tracker
medTracker.addImage(myPicture, 0); // Tracks the image
Your paint() method can then check for the image's loading status. As you've already seen, most Web pages display a message where graphic images go while waiting on the images to arrive; you can read the waiting or file name message during the loading of the Web page's graphic image. The same will happen here, only instead of occurring at the Web page level, your applet will display the message until the image completely loads and then your applet will display the image all at once:
public void paint(Graphics g)
{
if (medTracker.checkID(0))
{
g.drawImage(myPicture, 0, 0, 100, 100, this);
}
else
{
g.drawString("Waiting for picture...", 0, 20);
}
}
As the rest of the applet executes, possibly executing a repaint() procedure now and then to execute paint() and update the screen, the Waiting for picture... message will go away only once the entire image loads into the applet's running work area. If you did not check the image status but simply wrote the paint() method with the drawString() preceding the drawImage(), the image slowly overwrites the Waiting for picture... message as the image loads and displays on the applet's screen. Of course, you may want an image to do that depending on your applet's goals, but the checkID() methods let you suspend your image displays until you receive the full image from their source.
Efficient Boolean Tests
The statusID() and statusAll() methods return more information than the simple boolean result of checkID() and checkAll(). Assign the statusID() and statusAll() methods to an integer variable like this if you want to learn more about the loading status:
loadStat = medTracker.statusID(0, true); // Loads and tests all
[ic:ccc]0 images
The return integer value will be equal to one of the predefined named constants described in table 15.2.
Table 15.2 The MediaTracker's Status Return Values
Parameter | Description |
MediaTracker.ABORTED | Returns if one or more of the tracked images aborted the load process (such as will happen if the URL went down). |
MediaTracker.COMPLETE | Returns once the tracked images completely load. |
MediaTracker.LOADING | Returns if one or more tracked images are still loading. |
MediaTracker.ERRORED | Returns if an error occurred during the loading of any tracked image. |
If you want to manipulate your loaded graphic images, you can use one of the several filters Visual J++ supports. An image filter overlays your applet's image and changes the image's appearance to the end-user.
Before using an image filter, you must make sure that you import the correct class library that supports filtering. Before you can use a filter, you must Import the java.awt.image class package like the following:
import java.awt.image.*; // Import the class package
It might seem strange that you have to import both the java.awt.* class packages and the java.awt.image.* class package. The wildcard, *, works as a wildcard only for classes and not for additional class packages. In other words, the following statement imports classes such as java.awt.Frame and java.awt.Graphics because Frame and Graphics are classes within the Java.awt class package; but, the following statement does not import classes from the java.awt.image.* class package:
import java.awt.*; // Cannot import a class package, only classes
One of the most important filters is the cropping filter. You'll recall from the first section in this chapter that you can control the size of a loaded graphic image by setting width and height parameters inside the drawImage() method. If you pass a width or height parameter that makes the image smaller than the .Gif image takes on its own, your applet will not crop the image but will shrink the image. If you want to crop the image, create an ImageFilter object and make the object crop your image so the image's edges appear cut off from the rest of the image itself.
The following statement instantiates a cropping ImageFilter object:
ImageFilter cropImageFilt; // Instantiates an image filter
You must also instantiate a new Image object that will hold the cropped image, as done in the following statement:
Image myCroppedImage;
Once you load your image with getImage(), you must set the image filter to a cropping filter (several other filters are available) by creating a new cropped filter like this:
cropImageFilt = new CropImageFilter(100, 70, 185, 180);
The following is the format of the CropImageFilter() constructor method:
CropImageFilter(int x, int y, int width, int height);
The x- and y-coordinates tell the filter where to begin cropping on the full image. The width parameter describes the width to crop, in pixels, and the height describes the height to crop. Therefore, the previous CropImageFilter() method starts cropping the image at coordinate 100, 70 and crops the image for a width of 185 pixels and a height of 180 pixels.
The CropImageFilter() creates the correct cropping filter but does not yet crop the image. Instead of modifying the image, you'll create a new cropped image using createImage() like this:
myCroppedImage = createImage(new
[ic:ccc]FilteredImageSource(myPicture.getSource(), cropImaeFilt));
Now that you've created the cropped image, you can display the cropped image using the g.drawImage() method. If you were to manipulate the Animals.gif image shown throughout this chapter and crop the image as described in this section, then display both the cropped and the uncropped image on an applet, you'll see something like the applet in figure 15.2.
Displaying a cropped and uncropped image.
As described in chapter 6, "Reviewing the Sample Code," Visual J++ includes several sample programs that demonstrate the graphics capabilities of the Java language. You might want to refer back to chapters 6 and 7 now that you've gained more insight into Visual J++-based graphics to see what's in store as you learn more about programming in Java. Although animation is a fairly advanced topic, you can now study the Bouncing Heads source file to see how to produce animated applet pages. Remember that your applets run as fast as your end-users' computers will allow, so animation is no longer bound by slow download times across the Internet.
The goal of this chapter is to teach you how to display and manipulate graphic images files inside your Visual J++ applications. Certainly you don't want to draw every graphic element, pixel by pixel, using the primitive graphic methods described in chapter 14. If you've got the image files to display, use the drawImage() method to draw that image on your applet's page. The primitive graphic methods are great for adding dividing lines, circled backgrounds, and colored patterns to your applet. You'll want to use this chapter's methods for loading scanned images, which will really make your Web pages appealing.
There's so much more to graphics than this book can cover. Nevertheless, you are well on your way to becoming a professional Java programmer using Visual J++'s Developer Studio. Study the graphics-related sample files that come with Visual J++ to learn what's in store as you hone your Visual J++ skills.
The next chapter begins a new part of the book that looks at special Visual J++ topics. By adding exceptions to your code, you'll capture runtime errors that could crop up now and then. Threaded programming, although tricky, will let your applets run more smoothly than they otherwise might. In addition, you'll learn about the exciting new ActiveX and COM technologies that only Visual J++ offers for the Java-based Web developer.
Here are the points this chapter covered:
| Previous Chapter | Next Chapter |
| Table of Contents | Book Home Page |
| Que Home Page | Digital Bookshelf | Disclaimer |
To order books from QUE, call us at 800-716-0044 or 317-361-5400.
For comments or technical support for our books and software, select Talk to Us.
© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.