by Hiro Ruo
This chapter presents the basic multimedia capabilities provided with the Java Developer's Kit (JDK). The following topics are discussed:
One of the most popular uses of the Web is as a publishing tool. The Web is a plethora of corporate propaganda, product advertisements, and information distribution. To aid in the presentation of this information, multimedia content is widely used.
Multimedia is the integration of several types of media. It is typically associated with the combination of graphics and audio contents, and ultimately full animation. This sensually stimulating form of media can be a powerful tool when implemented as content for a Web page.
Java provides facilities to implement graphics and audio in an applet. These features are explored in Chapter 32, "Extending Multimedia Capabilities Through ActiveX." First you will look at how graphical images can be retrieved and displayed from within an applet. Then, you will explore how audio content can be added to an applet so that sound files will be playing when the Web page is opened. Finally, you will integrate these features in an applet to create animation with audio simultaneously.
To display an image, the image must first be retrieved. Java supports the retrieval of images with a few commands.
GetGraphics() creates a graphics context for drawing to an offscreen image. This method can only be called for offscreen images, which are created with the createImage method with two integer arguments. In the code shown in the examples in this chapter, getGraphics() is called to create a graphics context while downloading the images offscreen. The return values of getGraphics() is a graphics context to draw to the off-screen image. If for some reason the graphics were not loaded properly, getGraphics().drawString can be called to visually notify that an error condition has occurred.
GetImage(filename) is the command called to retrieve the actual image files. Given the filename in String format, getImage will retrieve the specified files. In the following example, the getImage command is called in different contexts. In a standalone applet, the toolkit getImage is called with the filename as the parameter. In an applet, getImage should be called with the getDocumentBase return values as a parameter. The getDocumentBase command will return the URL of the referencing document that contains the applet. You can also call a similar command, getCodeBase, which returns the URL of the applet.
These commands set up the environment by which filenames can be indexed in the code. Upon a successful call to getImage, the image with the pixel data referenced by the filename is returned. Note also that the filename does not have to be locally stored; the getImage syntax allows a URL to a remote filename to be the parameter passed. This is how an image can be retrieved remotely to be displayed on the Web page being developed.
To check the status of the image retrievals, the m_fAllLoaded flag is provided. This flag is updated as files-in this case, images-are downloaded. If the required images are not yet completely downloaded, the m_fAllLoaded flag is FALSE (0). When all the required files have completely downloaded successfully, the flag is then set to TRUE (1). This can be used as an error checking mechanism: If the point in the code at which the files should have been downloaded is reached and the m_fAllLoaded flag is still false, then an error during the download has occurred, and the user should be notified.
The first example examines the implementation of these functions and flags. Note that the examples in this chapter list only the main classes. The Visual J++ Applet Wizard also creates a *Frame.class file associated with the project workspace. No modifications were done to this file for these examples, but this class is required for the applet to function correctly.
When the required images are downloaded for the applet/application, the images will be displayed accordingly. The following sections describe this process.
First, you must define a window where the image or any other screen content will be displayed. This is accomplished with a resize(x,y) command. Resize() will create an active window of horizontal size x pixels and vertical size y pixels for the applet/application. Any subsequent calls to put content on the display should be directed to this window. Any image larger than the defined size will not be displayed on the screen completely.
In addition, a Graphic Context must be referenced (denoted by the variable g in Listing 31.1). The graphics context is the space in which any commands to display something on the screen are performed. For example, if you wish to display text on the screen, g.drawImage(String,x,y) will be called to display the text String in the window defined at coordinate (x,y).
Listing 31.1. An image retrieval and display applet.
import java.applet.*;
import java.awt.*;
import ImageSortFrame;
public class ImageSort extends Applet implements Runnable
{
Thread m_ImageSort = null;
private Graphics m_Graphics;
private Image m_Images[];
private int m_nCurrImage;
private int m_nImgWidth = 0;
private int m_nImgHeight = 0;
private boolean m_fAllLoaded = false;
private final int NUM_IMAGES = 9;
boolean m_fStandAlone = false;
private String m_ImageFile[] = new String[NUM_IMAGES];
private final String PARAM_ImageFile1 = "ImageFile1";
private final String PARAM_ImageFile2 = "ImageFile2";
private final String PARAM_ImageFile3 = "ImageFile3";
private final String PARAM_ImageFile4 = "ImageFile4";
private final String PARAM_ImageFile5 = "ImageFile5";
private final String PARAM_ImageFile6 = "ImageFile6";
private final String PARAM_ImageFile7 = "ImageFile7";
private final String PARAM_ImageFile8 = "ImageFile8";
private final String PARAM_ImageFile9 = "ImageFile9";
String GetParameter(String strName, String args[])
{
if (args == null)
{
return getParameter(strName);
}
int i;
String strArg = strName + "=";
String strValue = null;
for (i = 0; i < args.length; i++)
{
if (strArg.equalsIgnoreCase(args[i].substring(0, strArg.length())))
{
strValue= args[i].substring(strArg.length());
if (strValue.startsWith("\""))
{
strValue = strValue.substring(1);
if (strValue.endsWith("\""))
strValue = strValue.substring(0, strValue.length() - 1);
}
}
}
return strValue;
}
void GetParameters(String args[])
{
String param;
param = GetParameter(PARAM_ImageFile1, args);
if (param != null)
m_ImageFile[0] = param;
param = GetParameter(PARAM_ImageFile2, args);
if (param != null)
m_ImageFile[1] = param;
param = GetParameter(PARAM_ImageFile3, args);
if (param != null)
m_ImageFile[2] = param;
param = GetParameter(PARAM_ImageFile4, args);
if (param != null)
m_ImageFile[3] = param;
param = GetParameter(PARAM_ImageFile5, args);
if (param != null)
m_ImageFile[4] = param;
param = GetParameter(PARAM_ImageFile6, args);
if (param != null)
m_ImageFile[5] = param;
param = GetParameter(PARAM_ImageFile7, args);
if (param != null)
m_ImageFile[6] = param;
param = GetParameter(PARAM_ImageFile8, args);
if (param != null)
m_ImageFile[7] = param;
param = GetParameter(PARAM_ImageFile9, args);
if (param != null)
m_ImageFile[8] = param;
}
public static void main(String args[])
{
ImageSortFrame frame = new ImageSortFrame("ImageSort");
frame.show();
frame.hide();
frame.resize(frame.insets().left + frame.insets().right + 320,
frame.insets().top + frame.insets().bottom + 240);
ImageSort applet_ImageSort = new ImageSort();
frame.add("Center", applet_ImageSort);
applet_ImageSort.m_fStandAlone = true;
applet_ImageSort.GetParameters(args);
applet_ImageSort.init();
applet_ImageSort.start();
frame.show();
}
public ImageSort()
{
}
public String getAppletInfo()
{
return "Name: ImageSort\r\n" +
"Author: Hiro Yueh-Hung Ruo\r\n" +
"Created with Microsoft Visual J++ Version 1.0";
}
public String[][] getParameterInfo()
{
String[][] info =
{
{ PARAM_ImageFile1, "String", "Parameter description" },
{ PARAM_ImageFile2, "String", "Parameter description" },
{ PARAM_ImageFile3, "String", "Parameter description" },
{ PARAM_ImageFile4, "String", "Parameter description" },
{ PARAM_ImageFile5, "String", "Parameter description" },
{ PARAM_ImageFile6, "String", "Parameter description" },
{ PARAM_ImageFile7, "String", "Parameter description" },
{ PARAM_ImageFile8, "String", "Parameter description" },
{ PARAM_ImageFile9, "String", "Parameter description" },
};
return info;
}
public void init()
{
int i;
if (!m_fStandAlone)
GetParameters(null);
resize(320, 240);
}
private void displayImage(Graphics g)
{
if (!m_fAllLoaded)
return;
g.drawImage(m_Images[m_nCurrImage],
(size().width - m_nImgWidth[m_nCurrImage]) / 2,
(size().height - m_nImgHeight[m_nCurrImage]) / 2, null); }
public void paint(Graphics g)
{
if (m_fAllLoaded)
{
Rectangle r = g.getClipRect();
g.clearRect(r.x, r.y, r.width, r.height);
displayImage(g);
}
else
g.drawString("Loading images...", 10, 20);
}
public void start()
{
if (m_ImageSort == null)
{
m_ImageSort = new Thread(this);
m_ImageSort.start();
}
}
public void stop()
{
if (m_ImageSort != null)
{
m_ImageSort.stop();
m_ImageSort = null;
}
}
public void run()
{
m_nCurrImage = 0;
if (!m_fAllLoaded)
{
repaint();
m_Graphics = getGraphics();
m_Images = new Image[NUM_IMAGES];
MediaTracker tracker = new MediaTracker(this);
String strImage;
for (int i = 1; i <= NUM_IMAGES; i++)
{
strImage = "images/" + m_ImageFile[i-1];
if (m_fStandAlone)
m_Images[i-1] = Toolkit.getDefaultToolkit()
.getImage(strImage);
else
m_Images[i-1] = getImage(getDocumentBase(), strImage);
tracker.addImage(m_Images[i-1], 0);
}
try
{
tracker.waitForAll();
m_fAllLoaded = !tracker.isErrorAny();
}
catch (InterruptedException e)
{
}
if (!m_fAllLoaded)
{
stop();
m_Graphics.drawString("Error loading images!", 10, 40);
return;
}
for (int i = 0; i < NUM_IMAGES; i++)
{
m_nImgWidth[i] = m_Images[i].getWidth(this);
m_nImgHeight[i] = m_Images[i].getHeight(this);
}
}
repaint();
while (true)
{
try
{
displayImage(m_Graphics);
Thread.sleep(50);
}
catch (InterruptedException e)
{
stop();
}
}
}
public boolean mouseDown(Event evt, int x, int y)
{
repaint();
m_nCurrImage++;
if (m_nCurrImage == NUM_IMAGES)
m_nCurrImage = 0;
return true;
}
}
For each image to be displayed, there must be a corresponding Image object associated with it. This Image object is the reference to the image to be displayed. With each image is a corresponding Image Observer. This is the construct that contains the attributes of the image, including the Width, Height, and other properties of the image. The Image Observer is accessed to obtain the pixel size of the image after it is loaded.
When the Image is defined by a reference to a certain image file, it can be displayed. The command to put the image on the screen in the active window of the applet/application is the drawImage() command. Its syntax follows:
drawImage(Image, x, y, backgroundColor, Image Observer);
The image object Image is displayed at coordinates (x,y) in reference to the active window from the upper-left corner. The optional parameter backgroundColor can be specified to indicate what color the transparent pixels in the image will display. The Image Observer is set to this to indicate the current image context. DrawImage() is called within the realm of the graphics context g.
Currently, standard Java will support the display of GIF and JPEG files. Files can be converted to these formats using a variety of graphics tools available today, such as PaintShop Pro or CorelDRAW!.
Note that in the following example, a function paint() is called. This command is a primitive for repainting the screen and is used when displaying images for animation. Also, note that a Frame is defined for the applet/application. This is to support running this program as a standalone application. This is how an image file can be displayed.
Now let's look at Listing 31.2. In this example of a program, a series of image files are displayed in the active window while giving the user control of the sequence of display. Using the mouseDown() primitive, you can allow the user to parse through an array of Images. This example shows a common method by which image files can be retrieved and displayed. In addition, it demonstrates using parameters to pass image filenames to the applet/application, so that any change in which image to display can be implemented simply by editing the HTML file's parameter entries. Listing 31.2 also sets the stage for animation. It constantly repaints the image, awaiting input from the user. This is the method in which a series of images can be displayed to form animation.
The HTML file in Listing 31.2 is used to run the applet/application of Listing 31.1. It passes the applet a set of image files. The images are displayed in the sequence from ImageFile1 to ImageFile9 and repeated.
Listing 31.2. An image retrieval and display HTML.
<html>
<head>
<title>ImageSort</title>
</head>
<body>
<hr>
<applet
code=ImageSort.class
id=ImageSort
width=320
height=240 >
<param name=ImageFile1 value="img0001.gif">
<param name=ImageFile2 value="img0002.gif">
<param name=ImageFile3 value="img0003.gif">
<param name=ImageFile4 value="img0004.gif">
<param name=ImageFile5 value="img0005.gif">
<param name=ImageFile6 value="img0006.gif">
<param name=ImageFile7 value="img0007.gif">
<param name=ImageFile8 value="img0008.gif">
<param name=ImageFile9 value="img0009.gif">
</applet>
<hr>
<a href="ImageSort.java">The source.</a>
</body>
</html>
The resulting Web page displayed by accessing the above HTML file with a Web browser (in this case, Netscape 2.0) is shown in Figure 31.1. With each mouse click in the applet window, a different image as indexed by the HTML file is displayed. This is a simple application that allows you to present graphical content in a Web page using an applet/application.
Figure 31.1 : Image retrieval and display applet.
With a few modifications to the above code ImageSort.java,
you can display images in a more flexible manner. An example would
be to pass an additional integer parameter to indicate how many
parameters, or image filenames, will be passed to the applet.
The applet then must be modified to accept this first parameter
to determine the size of the parameter and Image arrays
to create so that the files can then be retrieved properly.
| Note |
The image in Figure 31.1 and others used in this example were obtained from the LAL Aviation Archives located at http://lal.cs.byu.edu/planes/planes.html |
Now that you can retrieve images and display them, let's look at another aspect of multimedia-the audio content.
The retrieval and playback of audio is quite a bit simpler than the image display support. There are three simple, common ways to retrieve, play, and manipulate audio clips.
Play() is the command used to play an audio clip once. This command is demonstrated in Listing 31.3. On each instance of this function in a program, the audio clip is started. The standalone syntax of play()follows:
play(URL, audiofile);
Listing 31.3. An audio retrieval and play applet.
import java.applet.*;
import java.awt.*;
import AudioPlayFrame;
public class AudioPlay extends Applet implements Runnable
{
Thread m_AudioPlay = null;
boolean m_fStandAlone = false;
private String m_AudioFile = "";
AudioClip backmusic;
private final String PARAM_AudioFile = "AudioFile";
String GetParameter(String strName, String args[])
{
if (args == null)
{
return getParameter(strName);
}
int i;
String strArg = strName + "=";
String strValue = null;
for (i = 0; i < args.length; i++)
{
if (strArg.equalsIgnoreCase(args[i].substring(0, strArg.length())))
{
strValue= args[i].substring(strArg.length());
if (strValue.startsWith("\""))
{
strValue = strValue.substring(1);
if (strValue.endsWith("\""))
strValue = strValue.substring(0, strValue.length() - 1);
}
}
}
return strValue;
}
void GetParameters(String args[])
{
String param;
param = GetParameter(PARAM_AudioFile, args);
if (param != null)
m_AudioFile = param;
}
public static void main(String args[])
{
AudioPlayFrame frame = new AudioPlayFrame("AudioPlay");
frame.show();
frame.hide();
frame.resize(frame.insets().left + frame.insets().right + 320,
frame.insets().top + frame.insets().bottom + 240);
AudioPlay applet_AudioPlay = new AudioPlay();
frame.add("Center", applet_AudioPlay);
applet_AudioPlay.m_fStandAlone = true;
applet_AudioPlay.GetParameters(args);
applet_AudioPlay.init();
applet_AudioPlay.start();
frame.show();
}
public AudioPlay()
{
}
public String getAppletInfo()
{
return "Name: AudioPlay\r\n" +
"Author: Hiro Yueh-Hung Ruo\r\n" +
"Created with Microsoft Visual J++ Version 1.0\r\n" +
"Example for Chapter 31, Visual J++ Unleashed";
}
public String[][] getParameterInfo()
{
String[][] info =
{
{ PARAM_AudioFile, "String", "Parameter description" },
};
return info;
}
public void init()
{
if (!m_fStandAlone)
GetParameters(null);
resize(320, 240);
backmusic = getAudioClip(getDocumentBase(),"bomb.au");
}
public void destroy()
{
}
public void paint(Graphics g)
{
g.drawString("Click in Window to Hear Sound", 10, 20);
}
public void start()
{
if (m_AudioPlay == null)
{
m_AudioPlay = new Thread(this);
m_AudioPlay.start();
}
backmusic.loop();
}
public void stop()
{
if (m_AudioPlay != null)
{
m_AudioPlay.stop();
m_AudioPlay = null;
}
}
public void run()
{
while (true)
{
try
{
repaint();
Thread.sleep(50);
}
catch (InterruptedException e)
{
stop();
}
}
}
public boolean mouseDown(Event evt, int x, int y)
{
play(getCodeBase(),m_AudioFile);
return true;
}
public boolean mouseUp(Event evt, int x, int y)
{
return true;
}
}
A URL can be obtained by using either the getCodeBase() or getDocumentBase() functions, as described in the "Image Retrieval" and "Image Display" sections. Again, this is the simple method by which remote files, in this case audio files, can be indexed by an application.
Stop() is the command used to stop the play of an audio file that is currently playing. This function is useful to allow larger audio files to be loaded but stopped, depending on the context of the applet.
The loop() command is used if an audio file is to be played continuously. When a loop() is used to initiate the play of an audio file, the file will play from the beginning once again after the file has completed playing. The standalone syntax of loop()follows:
loop(URL, audiofile);
An example of using this function is to play an audio file while a Web page is being used. Listing 31.3 demonstrates this by opening an audio file for play when it starts.
When either loop() or play() is called, the audio file will download. This audio file is then loaded into memory, so that on future instances of calling this audio file, downloading is not necessary. A better method of retrieving audio clips is with the getAudioClip() command. If an object AudioClip is defined within a program, any calls of play(), stop(), or loop() to that object will result in manipulation of only that audio clip. The getAudioClip() is called as follows:
getAudioClip(audiofile);
Again, audiofile can be either a local file or a remote file accessed with a URL.
Multiple audio clips can be played simultaneously. With each instance of play() or loop(), an audio file specified will be loaded (if it is not already) and played. While this audio file is playing, any additional instances of the same file or other audio files can also be called. The simultaneous play of audio clips is limited only by the audio subsystem in your PC.
Note also that the AU audio format is the default and only support. If a WAV or other audio file is to be played, it must be converted into the AU format. The sampling rate of the AU file supported should also be set to 8K. Tools to do this are available on the Web. Check out the Windows 95 Shareware Web site at http://www.windows95.com/apps/sound.html for some shareware audio utilities.
Listing 31.3 presents an applet that opens a window of 320´240 pixels in which bomb bursts, or any other audio file, are played continuously when the applet opens. This is accomplished by calling getAudioClip() in the init() function and loop() in start(). If the mouse button is clicked anywhere in the active window, the audio file specified by the parameter plays. This simple example illustrates the flexibility with which audio files can be used: either as background music or as a sensory indicator of an action taking place (in this case, the mouse click). This audio model is used in the next section to illustrate the integration of both audio and video content into an animated multimedia applet.
The sections "Image Retrieval" and "Image Display " demonstrate how a series of image files can be displayed with the user controlling progress with the mouse. The section "Audio Retrieval and Playback," shows how audio files can be loaded and played within the context of an applet. Let's now combine these two multimedia primitives into an animation applet/application.
What is animation? It is simply a series of images presented in a continuous sequence. In cartoons, the pictures are not actually moving; rather, a large number of images closely related to the previous and following images are displayed at a high enough sequential speed that the result is the semblance of motion. Animation on a computer is similarly accomplished. Animation is simply one image after another displayed in sequence without any interaction from the user.
What gives us the pseudomotion in animation is the relationships of the images within the sequence. This can be accomplished either by creating distinct images frame by frame and selecting the sequence in which they will be displayed, or by manipulating a single image file. This section demonstrates the use of animation utilizing the methods previously demonstrated in image retrieval and display.
The integration of audio content enhances the animation with sound, giving an applet/application true multimedia presentation features. In the following example, audio file retrieval and playback are synchronized with the animation.
The secret to animation is the capability to constantly refresh the screen and display a new image; so you must find a way to display images one after the other without interruption. To accomplish this, all the images must be completely loaded to ensure that the image can be displayed using the imageUpdate() command. The imageUpdate() command will check if the image files are loaded before display, returning a false if the image files required are not loaded yet. This will ensure that the images are in memory and ready for use.
In addition to ensuring that the images are available, there must be a method to refresh the screen so that any previous content is cleared off the screen. The paint() command is then required. This command is called on any repaint() call. The operations in a paint() call determine how the screen will be refreshed. In the following example, paint() will clear the active window with the selected background color and repaint the current image. Therefore, on any repaint() issued, the screen is cleared back to just the background color, and the current image being displayed is repainted, giving the display a clean image.
All that needs to be done now is to create the sequence of animation.
First, Listing 31.4 "slides" the image file display from the left side of the active window to the center of the screen. This is accomplished by dynamically changing the location at which the image file is displayed. Recall from the previous sections that drawImage() is passed the coordinates (x,y). Changing these values in an organized, premeditated fashion will allow you to manipulate where the image shows on the screen. In this case, x is increased from 0 to the center value (calculated with the Image attribute Width in relation to the active window size) while keeping y constant. This is a simple example of how to animate objects by manipulating a single image file.
Next, Listing 31.4 creates animation by displaying several images in a predetermined sequence with predetermined timing. The variable m_ImageFlag determines this sequence. In the example, the images are displayed according to the index of this array. The program sequentially indexes each m_ImageFlag array item to determine which of the ImageFiles to display. In this sequence, the animation is created because the images are related to the previous and following images.
To add audio content, we used the same method as described in the "Audio Retrieval and Playback" section. However, in this case, the audio initiation must be synchronized to the images being displayed. This is done by calling play() at the appropriate location in the program. It is predetermined which image file changes will result in an animation action that will have an audio content associated with it. On these change sequences, play() is called and the AudioClip indexed. To properly time the audio end to the next animation sequences, additional still frames are inserted until the audio file has completed playing. This will require some experimentation. A better method would be to use shorter AudioClips and trigger the playback within the code. In this example, the bomb.au file can be broken into two pieces, and the actual explosion can be played back using play() at the appropriate indexed image of m_ImageFlag.
Listing 31.4. An animation applet.
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import AnimationFrame;
public class Animation extends Applet implements Runnable
{
Thread m_Animation = null;
private Graphics m_Graphics;
private Image m_Images[];
private int m_nCurrImage;
private boolean m_fAllLoaded = false;
private final int NUM_IMAGES = 8;
private final int NUM_AUDIO = 2;
private final int NUM_ITERATION = 80;
private int m_nImgWidth[] = new int[NUM_IMAGES];
private int m_nImgHeight[] = new int[NUM_IMAGES];
private AudioClip sound1;
private AudioClip sound2;
private boolean StopFlag;
boolean m_fStandAlone = false;
private String m_ImageFile[] = new String[NUM_IMAGES];
private String m_AudioFile[] = new String[NUM_AUDIO];
private int m_ImageFlag[] = {0,1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,3,4,5,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,7,6,7,
6,7,6,7,6,7,6,7,6,7,6,7,0,0};
private final String PARAM_AudioFile1 = "AudioFile1";
private final String PARAM_AudioFile2 = "AudioFile2";
private final String PARAM_ImageFile1 = "ImageFile1";
private final String PARAM_ImageFile2 = "ImageFile2";
private final String PARAM_ImageFile3 = "ImageFile3";
private final String PARAM_ImageFile4 = "ImageFile4";
private final String PARAM_ImageFile5 = "ImageFile5";
private final String PARAM_ImageFile6 = "ImageFile6";
private final String PARAM_ImageFile7 = "ImageFile7";
private final String PARAM_ImageFile8 = "ImageFile8";
String GetParameter(String strName, String args[])
{
if (args == null)
{
return getParameter(strName);
}
int i;
String strArg = strName + "=";
String strValue = null;
for (i = 0; i < args.length; i++)
{
if (strArg.equalsIgnoreCase(args[i].substring(0, strArg.length())))
{
strValue= args[i].substring(strArg.length());
if (strValue.startsWith("\""))
{
strValue = strValue.substring(1);
if (strValue.endsWith("\""))
strValue = strValue.substring(0, strValue.length() - 1);
}
}
}
return strValue;
}
void GetParameters(String args[])
{
String param;
param = GetParameter(PARAM_AudioFile1, args);
if (param != null)
m_AudioFile[0] = param;
param = GetParameter(PARAM_AudioFile2, args);
if (param != null)
m_AudioFile[1] = param;
param = GetParameter(PARAM_ImageFile1, args);
if (param != null)
m_ImageFile[0] = param;
param = GetParameter(PARAM_ImageFile2, args);
if (param != null)
m_ImageFile[1] = param;
param = GetParameter(PARAM_ImageFile3, args);
if (param != null)
m_ImageFile[2] = param;
param = GetParameter(PARAM_ImageFile4, args);
if (param != null)
m_ImageFile[3] = param;
param = GetParameter(PARAM_ImageFile5, args);
if (param != null)
m_ImageFile[4] = param;
param = GetParameter(PARAM_ImageFile6, args);
if (param != null)
m_ImageFile[5] = param;
param = GetParameter(PARAM_ImageFile7, args);
if (param != null)
m_ImageFile[6] = param;
param = GetParameter(PARAM_ImageFile8, args);
if (param != null)
m_ImageFile[7] = param;
}
public static void main(String args[])
{
AnimationFrame frame = new AnimationFrame("Animation");
frame.show();
frame.hide();
frame.resize(frame.insets().left + frame.insets().right + 320,
frame.insets().top + frame.insets().bottom + 240);
Animation applet_Animation = new Animation();
frame.add("Center", applet_Animation);
applet_Animation.m_fStandAlone = true;
applet_Animation.GetParameters(args);
applet_Animation.init();
applet_Animation.start();
frame.show();
}
public Animation()
{
}
public String getAppletInfo()
{
return "Name: Animation\r\n" +
"Author: Hiro Yueh-Hung Ruo\r\n" +
"Created with Microsoft Visual J++ Version 1.0";
}
public String[][] getParameterInfo()
{
String[][] info =
{
{ PARAM_AudioFile1, "String", "Parameter description" },
{ PARAM_AudioFile2, "String", "Parameter description" },
{ PARAM_ImageFile1, "String", "Parameter description" },
{ PARAM_ImageFile2, "String", "Parameter description" },
{ PARAM_ImageFile3, "String", "Parameter description" },
{ PARAM_ImageFile4, "String", "Parameter description" },
{ PARAM_ImageFile5, "String", "Parameter description" },
{ PARAM_ImageFile6, "String", "Parameter description" },
{ PARAM_ImageFile7, "String", "Parameter description" },
{ PARAM_ImageFile8, "String", "Parameter description" },
};
return info;
}
public void init()
{
int i;
if (!m_fStandAlone)
GetParameters(null);
resize(320, 240);
sound1 = getAudioClip(getDocumentBase(),m_AudioFile[0]);
sound2 = getAudioClip(getDocumentBase(),m_AudioFile[1]);
StopFlag = true;
}
public void destroy()
{
}
public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h)
{
if (m_fAllLoaded)
return false;
if ((flags & ALLBITS) == 0)
return true;
if (++m_nCurrImage == NUM_IMAGES)
{
m_nCurrImage = 0;
m_fAllLoaded = true;
}
return false;
}
private void displayImage(Graphics g)
{
if (!m_fAllLoaded)
return;
g.drawImage(m_Images[m_ImageFlag[m_nCurrImage]],
(size().width - m_nImgWidth[m_ImageFlag[m_nCurrImage]]) / 2,
(size().height - m_nImgHeight[m_ImageFlag[m_nCurrImage]]) / 2,
null);
}
private void displayImage2(Graphics g, int x)
{
if (!m_fAllLoaded)
return;
g.drawImage(m_Images[m_ImageFlag[m_nCurrImage]],
x, (size().height - m_nImgHeight[m_ImageFlag[m_nCurrImage]]) / 2, null);
}
public void paint(Graphics g)
{
if (m_fAllLoaded)
{
Rectangle r = g.getClipRect();
g.clearRect(r.x, r.y, r.width, r.height);
displayImage(g);
}
else
g.drawString("Loading images...", 10, 20);
}
public void start()
{
if (m_Animation == null)
{
m_Animation = new Thread(this);
m_Animation.start();
}
}
public void stop()
{
if (m_Animation != null)
{
m_Animation.stop();
m_Animation = null;
}
}
public void run()
{
m_nCurrImage = 0;
if (!m_fAllLoaded)
{
repaint();
m_Graphics = getGraphics();
m_Images = new Image[NUM_IMAGES];
MediaTracker tracker = new MediaTracker(this);
String strImage;
for (int i = 1; i <= NUM_IMAGES; i++)
{
strImage = "images/" + m_ImageFile[i-1];
if (m_fStandAlone)
m_Images[i-1] = Toolkit.getDefaultToolkit()
.getImage(strImage);
else
m_Images[i-1] = getImage(getDocumentBase(), strImage);
tracker.addImage(m_Images[i-1], 0);
}
try
{
tracker.waitForAll();
m_fAllLoaded = !tracker.isErrorAny();
}
catch (InterruptedException e)
{
}
if (!m_fAllLoaded)
{
stop();
m_Graphics.drawString("Error loading images!", 10, 40);
return;
}
for (int i = 0; i < NUM_IMAGES; i++)
{
m_nImgWidth[i] = m_Images[i].getWidth(this);
m_nImgHeight[i] = m_Images[i].getHeight(this);
}
}
repaint();
for (int i=32; i>0; i-)
{
displayImage2(m_Graphics,
(size().width - m_nImgWidth[m_ImageFlag[m_nCurrImage]])-(10*i));
}
repaint();
while (StopFlag)
{
try
{
m_nCurrImage++;
if (m_nCurrImage == NUM_ITERATION)
m_nCurrImage = 0;
displayImage(m_Graphics);
if ((m_nCurrImage==1) || (m_nCurrImage==3) || (m_nCurrImage==5))
sound1.play();
if (m_nCurrImage==14)
sound2.play();
Thread.sleep(50);
}
catch (InterruptedException e)
{
stop();
}
}
}
public boolean mouseDown(Event evt, int x, int y)
{
sound1.stop();
sound2.stop();
StopFlag = false;
return true;
}
}
The HTML file described in Listing 31.5 is used by the selected Web browser (in this case, Netscape 2.0) to run the applet. It again passes the filenames of the audio and image files to the applet as parameters, making this program flexible enough that other images and audio files can also be used to create the animation. With some minor changes to the code, the animation sequence can also be passed through this method. This additional implementation can make this a generic animation program, in which the content developer can select the sequence and audio and image used without recompiling the code. Listing 31.5 shows the HTML file created that can be used to run the applet of Listing 31.4 in a Web page.
Listing 31.5. An animation applet HTML.
<html>
<head>
<title>Animation</title>
</head>
<body>
<hr>
<applet
code=Animation.class
id=Animation
width=320
height=240 >
<param name=AudioFile1 value="Audio/gun-shot.au">
<param name=AudioFile2 value="Audio/bomb.au">
<param name=ImageFile1 value="img0001.gif">
<param name=ImageFile2 value="img0002.gif">
<param name=ImageFile3 value="img0003.gif">
<param name=ImageFile4 value="img0004.gif">
<param name=ImageFile5 value="img0005.gif">
<param name=ImageFile6 value="img0006.gif">
<param name=ImageFile7 value="img0007.gif">
<param name=ImageFile8 value="img0008.gif">
</applet>
<hr>
<a href="Animation.java">The source.</a>
</body>
</html>
Figure 31.2 illustrates the animation accomplished in the sample program by manipulating the single image file. As you can see, the image appears to "slide" onto the screen.
Figure 31.2 : Animation with a single image file.
Figure 31.3 illustrates the animation of the sample program by sequentially displaying several related image files. Although not shown here, with certain frames (the second image with the firing of the gun, and the third and fourth frames of dropping and exploding the bomb), audio files are played and synchronized.
Figure 31.3 : Animation with multiple image files.
The use of image files and audio files can result in a powerful applet to be used in a Web page. With animation, or even simply displaying image files or playing back audio files, you can liven up the content of your Web page and help make it more noticeable. These techniques can be easily applied to a business environment, where advertisements can be sequentially displayed, potential customers can parse through a series of photos of the product being marketed, or "welcome" messages by the company president can be played. Or you can use these multimedia techniques to make your own personal Web page that much cooler.